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

Feature request: Private/Protected Files #215

Closed
bnert opened this issue Jul 25, 2022 · 15 comments
Closed

Feature request: Private/Protected Files #215

bnert opened this issue Jul 25, 2022 · 15 comments

Comments

@bnert
Copy link

bnert commented Jul 25, 2022

As the title suggests, are private/protected files currently scoped for 1.0.0 release? I was playing around with the files API, and as of right now, it seems like once files are uploaded they are considered public, unless I have missed something in the docs.

If this feature set is not implemented, are you open to a contribution for this feature?

As an aside, thank you so much for this project. It is AWESOME! 😃

@ganigeorgiev
Copy link
Member

ganigeorgiev commented Jul 25, 2022

That's correct - all files are considered public if the user have access to their url address. This recently was discussed in - #210.

Yes, I'm planning to add support for private/protected files. I'll use this issue and will add it to the roadmap, but for now it is a low priority.

Contributions are welcomed, but I'm not sure about the implementation details at the moment, so please feel free to share your idea before proceeding.

What I had in mind was to have a new endpoint that users could request to generate a short-lived/one-time tokens and pass this token as a query parameter to the file url where in the file serving endpoint we'll have to check if the related file field is protected or not and whether the user has access to it. The access permissions could be defined as an optional input (similar to the collection API rules). Note that we cannot use an authorization header, because it is not sent when requesting the file in a <img src="..."> tag for example.

@ganigeorgiev ganigeorgiev changed the title Roadmap Question: Are Private/Protected Files Scoped? Feature request: Private/Protected Files Jul 25, 2022
@newbeelearn
Copy link

If we had cookies for sesssion instead of token than this would become simpler to solve?

@ganigeorgiev
Copy link
Member

ganigeorgiev commented Jul 31, 2022

@newbeelearn It depends from a lot of things.

In order to pass the authorization token as cookie securely we will need to set at least the Secure and SameSite=Strict attributes because the other alternatives would require to implement some sort of CSRF protection, which'll further complicate sending requests to the API. And even if we use "SameSite=Strict" cookie then another problem arise and that's it from where the request originated - was it from the same domain? was it requested from a mobile app?, etc.

So while cookies could solve part of the problem they will also open a whole bunch of other issues that we'll have to take care.
I don't have anything against using cookies, but it is a lot easier to work with the API if they are not involved.

@bnert
Copy link
Author

bnert commented Aug 3, 2022

Agreed, I think a token is more apt. Nonetheless, a great question @newbeelearn!

I am going to think a bit more about implementation details and poke around the code to get a better idea of how this may be accomplished.

@ganigeorgiev
Copy link
Member

ganigeorgiev commented Aug 3, 2022

@bnert You could get a general idea how to generate the token and to restrict the file download action by following this example - #254 (comment)

The example is using the event hooks, but ideally something like this will be integrated in PocketBase itself with the main difference that instead of checking a single specific profile field, we would check a file API rule but the general idea is the same.

@bnert
Copy link
Author

bnert commented Aug 3, 2022

@ganigeorgiev, thanks for the reference. Really helpful! I'll have some time a couple weeks from now to take a deeper look and write out a design for this feature.

@jaredleishman
Copy link

If using an S3-compatible object storage, why not provide an option in the admin interface to use Signed URLs as the default? They could also provide an expiration time (or go with a 3600 second default). I know in Django the file field has a url property that uses a Signed URL by default for S3-compatible storage.

@ferryhtw
Copy link

ferryhtw commented Jan 6, 2023

Hi,
I'm new to this AWESOME!! PocketBase (2 week sofar),
As I still learning the mechanism of Pocketbase, based on this roadmaps, Is this mean people still able to access to the files after I have put following restrinction on OnFileDownloadRequest hookup?,
Is there any other way user can access to the files without proper login that I should aware of?

app.OnFileDownloadRequest().Add(func(e *core.FileDownloadEvent) error {

		authRecord, _ := e.HttpContext.Get(apis.ContextAuthRecordKey).(*models.Record)
		admin, _ := e.HttpContext.Get(apis.ContextAdminKey).(*models.Admin)

		if authRecord == nil && admin == nil {
			return apis.NewForbiddenError("Only authorized user can access view this file, please login first", e.FileField)
		}

		return nil
})

@jaredleishman
Copy link

@ferryhtw this likely won't do much because the requester will need to put the JWT in the header of the request and majority of the time requests will be initiated from an img tag's src attribute rather than using an http client like fetch.

If there was some sort of token you could attach as a query string and use that to restrict access then that could work. Or it would be cool if Pocketbase could return the file names with some sort of signature (think Signed URLs).

@ganigeorgiev
Copy link
Member

ganigeorgiev commented Jan 6, 2023

@ferryhtw Your hook is fine but it requires admin or auth record Authorization header for every file, and as @jaredleishman noted, the Authorization header is not send by default when the <img src> tag is used and your users will get 403 in your case (unless you "prefetch" the file).

Private/protected files will be implemented in v0.13/v014.

@charbs-io
Copy link

@ganigeorgiev - given 0.14 has now dropped, do you anticipate this to make it in 0.15?

@ganigeorgiev
Copy link
Member

@cayoub88 Yes, it is planned for the next release (there are no ETAs yet).

@ganigeorgiev
Copy link
Member

Support for private files is implemented in the develop branch.

It works with a short lived (~5min) file token passed as query param with the file url.
If the client associated with the token has "View API" rule access, then we'll return the file as usual, otherwise - return a 403 response. The same apply for the thumbs.

The SDKs are also updated with a new pb.files service to help with the file token generation (if you want to test it with the JS SDK you'll have to use JS SDK v0.14.0-rc; the Dart SDK will be updated sometime later today):

const token = await pb.files.getToken()

const url1 = pb.files.getUrl(record, filename1, { token })
const url2 = pb.files.getUrl(record, filename2, { token })
...

The changes will be shipped with the next v0.15.0 release (there are no ETAs yet).

@gacharles23
Copy link

I recently discovered PocketBase (while learning SvelteKit) and am incredibly thankful! Related to this particular feature, I’m sure I’m missing something because I seem to have found a way to programmatically access private files without a token - so long as the API rule is respected. I’m working on building an image sharing app, and my desire is that only owners of an image as well as any authorized sharers can view the image. I have an images table where each row contains basic info like description plus a file field. And a share_ids reference field linking to the users table. With a list/view API rule such as @request.auth.id ?= share_ids.id the code works perfectly - only permitted users can access the image records.

When I first implemented this, the file field was unprotected. Thus when an image was displayed for a user, the url could be lifted from the browser and pasted anywhere for public access. However, I then tried protecting the field via the Pocketbase Admin panel, and everything works as I hoped: images still display for users - so long as they are an owner or sharer - AND if you now extract the url from the browser and paste into a browser url, it returns a 403 error.

So, this is a long-winded way of asking why didn’t I need to go through the pb.files.getToken() flow for my app users to view the images? Mind you, I’m not complaining - I very much appreciate the current functionality - it is exactly as desired for this use case. But I’m sure there is something basic I’m missing. Thank you again. And my apologies if this is the wrong place to raise this question.

@ganigeorgiev
Copy link
Member

ganigeorgiev commented Apr 24, 2023

@gacharles23

So, this is a long-winded way of asking why didn’t I need to go through the pb.files.getToken() flow for my app users to view the images?

I don't understand what do you mean.

A file being marked "Protected" ensures that only requests that satisfy the View API rule of the collection will have access to the file.
If your View API rule is empty, then you don't need a file token since the resource will be accessible by everyone. If it is not empty, then a file token is required.
If that's not what you are experiencing, please file a new issue/discussion with reproducible steps and I'll try to investigate it.

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

No branches or pull requests

7 participants