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

Android issue 403 Error #334

Open
jsmueller7 opened this issue Dec 9, 2024 · 6 comments
Open

Android issue 403 Error #334

jsmueller7 opened this issue Dec 9, 2024 · 6 comments

Comments

@jsmueller7
Copy link

There's an issue on android devices; I've only tested with a couple of Cromium based browsers. On the older client version 1.1.2, if you select text and try to persist the annotation you'll get an error 403:

{
    "code": "42501",
    "details": null,
    "hint": null,
    "message": "new row violates row-level security policy for table \"bodies\""
}

If you test this in the exact same context/document with the exact same user, from a PC, you'll get a 201. This behavior is even shown if you try to usb debug from a computer. When creating the annotation with a computer mouse on the pc - in the inspected tab on the android device - the annotation will be created. If you try to create the annotation on the tablet / smartphone / screen, you'll get an 403.

The post-URL is the same, the authorization headers are the same.

@rsimon
Copy link
Member

rsimon commented Dec 9, 2024

Hi @jsmueller7, ok that's weird. It's definitely a permissions issue, meaning that the user's credentials are not getting through. Did you try clearing browser cache and cookies/localstorage on the Android device, to make absolutely sure there's not something intervening from our auth flow change that happened around v1.2?

Otherwise: if the credentials are leaving the device correctly, as you've confirmed with the USB debug, is there something that might happen in your Kong setup when the request comes in?

@jsmueller7
Copy link
Author

Hi @rsimon: I first tested on the older version with a device that never used the new auth flow. So that shouldn't have any influence. I can check what I see in kong. I guess though that this behavoir is reproducable on the performant staging environment as well. The other issue #335 is in the way though.

@jsmueller7
Copy link
Author

Allright, I have come further. I looked at Kong - the POST requests look exactly the same. The one request from the PC goes through, the one from the mobile device does not.

I noticed that: When I remote-debug my mobile browser, the annotation is created when I make the selection with the mouse from the PC. If I make the selection with my fingers, I get an error. After browsing through the tabs, I noticed that the only significant difference between successful and unsuccessful requests is the timing.

What also works in the mobile browser from the tablet is replying to existing comments. Only creating new annotations does not work.

Long story short: This must have something to do with the way text selection is handled on smart devices. With TEI / TXT the pop-up opens directly, with PDF the context menu of the mobile browser opens first - but only when I select with my fingers.

The Postgres logs fit into the picture because some timings are also logged there. Den genauen Zusammenhang kenne ich aber noch nicht.

postgresql  2024-12-11 12:49:38.880 UTC [20] LOG:  checkpoint starting: time
postgresql  2024-12-11 12:49:53.780 UTC [20] LOG:  checkpoint complete: wrote 149 buffers (0.9%); 0 WAL file(s) added, 0 removed, 0 recycled; write=14.745 s, sync=0.006 s, total=14.900 s; sync files=12, longest=0.006 s, average=0.001 s; distance=883 kB, estimate=1077 kB
postgresql 10.42.234.146 2024-12-11 12:51:51.887 UTC [1460993] supabase_admin@postgres ERROR:  new row violates row-level security policy for table "bodies"
postgresql 10.42.234.146 2024-12-11 12:51:51.887 UTC [1460993] supabase_admin@postgres STATEMENT:  WITH pgrst_source AS (INSERT INTO "public"."bodies"("annotation_id", "created_at", "created_by", "format", "id", "layer_id", "purpose", "updated_at", "updated_by", "value") SELECT "pgrst_body"."annotation_id", "pgrst_body"."created_at", "pgrst_body"."created_by", "pgrst_body"."format", "pgrst_body"."id", "pgrst_body"."layer_id", "pgrst_body"."purpose", "pgrst_body"."updated_at", "pgrst_body"."updated_by", "pgrst_body"."value" FROM (SELECT $1 AS json_data) pgrst_payload, LATERAL (SELECT CASE WHEN json_typeof(pgrst_payload.json_data) = 'array' THEN pgrst_payload.json_data ELSE json_build_array(pgrst_payload.json_data) END AS val) pgrst_uniform_json, LATERAL (SELECT "annotation_id", "created_at", "created_by", "format", "id", "layer_id", "purpose", "updated_at", "updated_by", "value" FROM json_to_recordset(pgrst_uniform_json.val) AS _("annotation_id" uuid, "created_at" timestamp with time zone, "created_by" uuid, "format" public.body_formats, "id" uuid, "layer_id" uuid, "purpose" character varying, "updated_at" timestamp with time zone, "updated_by" uuid, "value" text) ) pgrst_body  ON CONFLICT("id") DO UPDATE SET "annotation_id" = EXCLUDED."annotation_id", "created_at" = EXCLUDED."created_at", "created_by" = EXCLUDED."created_by", "format" = EXCLUDED."format", "id" = EXCLUDED."id", "layer_id" = EXCLUDED."layer_id", "purpose" = EXCLUDED."purpose", "updated_at" = EXCLUDED."updated_at", "updated_by" = EXCLUDED."updated_by", "value" = EXCLUDED."value" RETURNING 1) SELECT '' AS total_result_set, pg_catalog.count(_postgrest_t) AS page_total, array]::text] AS header, ''::text AS body, nullif(current_setting('response.headers', true), '') AS response_headers, nullif(current_setting('response.status', true), '') AS response_status FROM (SELECT * FROM pgrst_source) _postgrest_t
postgresql 10.42.234.146 2024-12-11 12:54:28.962 UTC [1460993] supabase_admin@postgres ERROR:  new row violates row-level security policy for table "bodies"
postgresql 10.42.234.146 2024-12-11 12:54:28.962 UTC [1460993] supabase_admin@postgres STATEMENT:  WITH pgrst_source AS (INSERT INTO "public"."bodies"("annotation_id", "created_at", "created_by", "format", "id", "layer_id", "purpose", "updated_at", "updated_by", "value") SELECT "pgrst_body"."annotation_id", "pgrst_body"."created_at", "pgrst_body"."created_by", "pgrst_body"."format", "pgrst_body"."id", "pgrst_body"."layer_id", "pgrst_body"."purpose", "pgrst_body"."updated_at", "pgrst_body"."updated_by", "pgrst_body"."value" FROM (SELECT $1 AS json_data) pgrst_payload, LATERAL (SELECT CASE WHEN json_typeof(pgrst_payload.json_data) = 'array' THEN pgrst_payload.json_data ELSE json_build_array(pgrst_payload.json_data) END AS val) pgrst_uniform_json, LATERAL (SELECT "annotation_id", "created_at", "created_by", "format", "id", "layer_id", "purpose", "updated_at", "updated_by", "value" FROM json_to_recordset(pgrst_uniform_json.val) AS _("annotation_id" uuid, "created_at" timestamp with time zone, "created_by" uuid, "format" public.body_formats, "id" uuid, "layer_id" uuid, "purpose" character varying, "updated_at" timestamp with time zone, "updated_by" uuid, "value" text) ) pgrst_body  ON CONFLICT("id") DO UPDATE SET "annotation_id" = EXCLUDED."annotation_id", "created_at" = EXCLUDED."created_at", "created_by" = EXCLUDED."created_by", "format" = EXCLUDED."format", "id" = EXCLUDED."id", "layer_id" = EXCLUDED."layer_id", "purpose" = EXCLUDED."purpose", "updated_at" = EXCLUDED."updated_at", "updated_by" = EXCLUDED."updated_by", "value" = EXCLUDED."value" RETURNING 1) SELECT '' AS total_result_set, pg_catalog.count(_postgrest_t) AS page_total, array]::text] AS header, ''::text AS body, nullif(current_setting('response.headers', true), '') AS response_headers, nullif(current_setting('response.status', true), '') AS response_status FROM (SELECT * FROM pgrst_source) _postgrest_t
postgresql  2024-12-11 12:54:38.842 UTC [20] LOG:  checkpoint starting: time
postgresql  2024-12-11 12:55:00.039 UTC [20] LOG:  checkpoint complete: wrote 212 buffers (1.3%); 0 WAL file(s) added, 0 removed, 0 recycled; write=21.044 s, sync=0.004 s, total=21.197 s; sync files=29, longest=0.004 s, average=0.001 s; distance=1228 kB, estimate=1228 kB

@rsimon
Copy link
Member

rsimon commented Dec 11, 2024

The timing (and, in fact, which events are thrown and which aren't) is definitely different on all platforms. (I'm tempted to say that the way different browsers behave is a mess... We've recently revised the whole selection handling code to account for it.)

So, I wouldn't be surprised about the timing differences. They should be ok in principle. (Although I suspect they play a role in the missing popup on Android and PDF!)

The permissions issue reported above must be something different.

  • First, I cannot see a way how the timing would influence the permissions, which would be determined by the user/auth info in the request.
  • Second: I'm now realizing the message is from the bodies table. When you create a new annotation, you wouldn't create a body. What happens instead is that you create records in the annotations and the targets table. But an insert in the bodies table would only happen after you type a message into the text box and hit Save.

@jsmueller7
Copy link
Author

With PDFs in the mobile browser I have this flow:

  • First I select text and the context menu appears (copy, web search etc.)
  • Then I expand the selection in order to make the pop-up appear.
  • Then I write text and send.

When I select text with the mouse, I basically only have just one interaction to make the pop-up appear.
With TEI and TXT, the pop-up appears immediately, at the expense of a chance for customizing the selection. But there is no error 403 there.

@rsimon
Copy link
Member

rsimon commented Dec 11, 2024

Thanks for the forensics! Then I believe we might actually just be facing a single bug here. (The missing popup in PDF/Android.) Because the popup isn't opening, the initial annotation (and target) are not getting created in the backend. As a follow-up, when you try to create a body, the permissions issue that you are seeing is because you are not attaching the body to an existing annotation that you have write permissions on. (Because there is no annotation.) I'm pretty sure that once we solved the frontend popup issue, the backend permissions will disappear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants