gristlabs / grist-core

Grist is the evolution of spreadsheets.
https://www.getgrist.com
Apache License 2.0
7.26k stars 321 forks source link

Allow to turn on public access for a single widget ? #348

Open yohanboniface opened 2 years ago

yohanboniface commented 2 years ago

Hi,

Just like we can export a single table widget in CSV or XLSX, we'd like to be able to harvest some data from a script automatically, but without needing to put the whole document in public access, and without needing to deal with tokens nor authentication.

In an ideal world, one would create a dedicated table widget, selecting the columns that they would make openly accessible, and then be able to copy the "download in CSV/XLSX" link to share it with someone else.

Would that make sense ?

Thanks again :)

Yohan

paulfitz commented 2 years ago

So from the security perspective, would that mean you'd like to include a sufficient token or other authorizing secret in the download URL? Feels like there needs to be some hard-to-guess component in the URL, or someone could scan a document for exposed material.

yohanboniface commented 2 years ago

You mean that if a document is partially public, and someone knows the document ID, they could guess the final download URL for each widget, until they find one public ?

Eg. this is how looks a download URL at this time:

https://mygrist.fr/o/anct/api/docs/ID12345678AZERTY/download/csv?viewSection=1&tableId=Zfu&activeSortSpec=%5B%5D&filters=%5B%5D

So when someone knows the ID (here ID12345678AZERTY), they will try to guess the other parameters ?

paulfitz commented 2 years ago

Yes, that is what I mean. The activeSortSpec could be set to something trivial, the viewSection could be brute forced (it is likely a small integer), and tableId might be guessable from context. Imagine user A grants access to some small sliver of a document to user B, and B is inquisitive. I'd feel more comfortable if there were something extra in the URL, like an unguessable token minted specially for this purpose. But maybe I'm being paranoid?

yohanboniface commented 2 years ago

OK, something like a query string parameter &token=xxx where xxx is salt derived from the document or something like that ?

LouisDelbosc commented 1 year ago

How are widget defined on the backend side ? Would it be possible to have an ID for this public view (if widgets have IDs) and with a get request you have the data, adding a url params you can have the json data (for the grid view). Or something like that.

Do you think it is possible @paulfitz ?

paulfitz commented 1 year ago

@LouisDelbosc something like you suggest is certainly possible. Widgets do have IDs (in the code they are often called view sections). There are lots of nice options for convenient endpoints to add. My main hang-up in this issue is about authentication. So far we have cookies, and an Authorization header using an api key. @yohanboniface is looking for a URL that can be used without needing to put the whole document in public access, and without needing to deal with tokens nor authentication. From my perspective, that means the URL needs to include something hard to guess. This is totally doable, e.g. with a token that Grist would add in the URL that it prepares for the download in CSV/XLSX link so that the URL can be used without cookies or an Authorization header. There is already code lying around in Grist for generating and respecting this kind of token.

dsagal commented 1 year ago

What about a variation of this approach, where access-giving tokens aren't automatically included, but require a separate step (like "Link-share widget"), and rather than produce a docId + token combination, this action would produce a single key that both identifies and gives access to this view?

In other words, the proposed design is:

  1. A new option in the widget menu to "Link-share widget...". It opens a dialog, which has a little explanation and a button to "Generate link". Once clicked, the same dialog shows the URL and a button to disable the link.
  2. The link would have the form https://docs.getgrist.com/w/abc123xyz/Widget-Title, i.e. similar to a doc URL, but using a newly-minuted UUID, without revealing the docID. This is useful because for link-shared documents, the docID itself is somewhat of a secret, and may give access to more data than I intend to by link-sharing one widget.
  3. In the spirit of Grist, access can remain at the data level, without restricting the format in which the data is accessible. So the dialog in step 1 can include a dropdown to select "Widget URL", "CSV link", "XLS link", "IFrame Embed Code".
  4. The widget dialog would offer a choice of permissions (as checkboxes or multi-select dropdown) to allow View, Add, Edit. While View would enable the format options described above, Add would enable an option Form submit URL. This could then be used in an HTML form to add data to this table (restricted to the columns visible in the widget).

The last point connects this request to the wish to support native forms. It would be a step towards supporting data collection via public forms, without requiring the user to learn access rules. Currently, using forms to collect data into Grist is possible (e.g. via https://github.com/gristlabs/grist-form-submit), but has the same difficulties as this issue brings up (requires putting whole document in public access and configuring access rules).

yohanboniface commented 1 year ago

I agree on this proposal, thanks for this!

yohanboniface commented 1 year ago

Not sure how this can be worked together, but here is a related need: sharing a whole page without sharing the document itself. In the example we've seen today, the need would be to share a whole page with charts widgets, as a dashboard, but without sharing the other pages (because some contains sensible data, like full name or phone numbers). Could this new "share dialog" also apply to a page or is it something totally different, at implementation level ?

paulfitz commented 1 year ago

Not sure how this can be worked together, but here is a related need: sharing a whole page without sharing the document itself. In the example we've seen today, the need would be to share a whole page with charts widgets, as a dashboard, but without sharing the other pages (because some contains sensible data, like full name or phone numbers). Could this new "share dialog" also apply to a page or is it something totally different, at implementation level ?

At an implementation level, to be secure, this requires some extra work. Currently any requests for data from the back-end are handled based on rules that refer to the underlying data - tables/columns/rows/cells. A page is kind of a fluid thing. It is constructed from a series of requests made by a web client, where one request may depend on the results of a previous one (e.g. with linked widgets). It is hard to pin down exactly what sharing only that page would mean - in general, you'd need to move more of the rendering of the page to the back-end, which could make it hard for the front-end to be flexible in the usual ways.

It could be that somewhat weaker restrictions could be adequate in many circumstances. Perhaps a page could offer an a lists of the queries it makes by default (particular sets of columns of particular tables with particular filter combinations) and we could offer a simple way to make all of those available. That would allow someone to make broader queries than the page ever might, since restrictions on the interactions between the queries wouldn't be captured, but that might be fine?

yohanboniface commented 1 year ago

Thanks for those details @paulfitz. That makes clear one thing: let's focus on sharing a given widget for now, and keep thinking. :)

paulfitz commented 1 year ago

As a first step, it would be possible to get about half-way to what you want using link keys: https://support.getgrist.com/access-rules/#link-keys

For example, we can take a document like: https://templates.getgrist.com/vAcfEKLQf3YF/Doggie-Daycare and add some access control rules so that non-owners can access certain columns of a certain table if they know a secret: https://docs.getgrist.com/cgcqKgbcLgVa/Doggie-Daycare-copy/p/1?Token_=abcd

The big drawback for your original application is that link keys have only been implemented yet for web viewing, they can't be presented when using Grist by the API. But that is simply because we never got around to it, not because it is difficult. It might in fact be quite easy. Would making link keys usable from the API be helpful to you @yohanboniface?

yohanboniface commented 1 year ago

Thanks for this suggestion @paulfitz! :)

My thoughts is that is a bit hidden for a "normal" user: to move back to the initial need, I'd like that the people maintaining the document can choose themselves which column will be made public or not, so creating a specific page with a table widget, where they will choose the columns, and that widget will then be made public.

Using the ACL will make this an advanced feature. But I'll continue thinking about it! Maybe that's anyway the shortest path to have a public version of a given table anyway. :)

paulfitz commented 1 year ago

We've been thinking about this some more, there are some notes at https://docs.getgrist.com/j3vnmtXw55HK/Half-baked-Sketches/p/1#a1.s6.r1.c6 - still not a firm design, mostly back-end thinking. Seems doable.