Skip to content

emilastanov/strapi-file-extention

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 

Repository files navigation

Strapi Upload Ownership Guard (Strapi v5.23.0)

Strapi Plugin License

A lightweight server-side extension for Strapi’s Upload plugin that enforces file ownership via a relation field owner pointing to plugin::users-permissions.user.

  • When an authenticated user uploads files via REST (POST /api/upload), the extension automatically attaches the uploader as the file owner.
  • When unauthenticated upload is allowed, uploaded files have owner = null and are treated as public in the Content API.
  • The Content API is restricted so that:
    • Authenticated users can see their own files and public files.
    • Unauthenticated users can see only public files.
    • findOne and delete are allowed only to the owner (or public for findOne).

This repository targets Strapi v5.23.0 and newer in the v5 line.


How it works

This extension customizes the Upload plugin in two places:

  1. Service wrapper (plugin.services.upload): after the Upload service persists files, it updates each created file using the Document Service to set:

    {
      "owner": { "connect": ["<currentUser.documentId>"] }
    }

    This avoids the Content API’s request body sanitation which ignores unknown fileInfo fields.

  2. Content API controller factory (plugin.controllers['content-api']): it wraps find, findOne, and destroy to enforce per-user access:

    • find filters with:
      { "$or": [ { "owner.documentId": user.documentId }, { "owner": null } ] }
      or { owner: null } if unauthenticated.
    • findOne / destroy verify that the loaded file either has owner = null (public) or owner.documentId = currentUser.documentId.

Compatibility

  • Strapi: v5.23.0 (tested)
  • Database: any supported by Strapi v5 (uses the Upload plugin’s files table and _links relation tables).
  • Users: relation is to Users & Permissions users (plugin::users-permissions.user). Admin users are not used for ownership checks.

Installation

This is a project-level extension. No npm install is required.

  1. In your Strapi project, create the following directory structure and copy the provided files:
src/
└─ extensions/
   └─ upload/
      ├─ content-types/
      │  └─ file/
      │     └─ schema.json      # full original Upload file schema + added "owner" relation
      └─ strapi-server.js       # service + controller factory wrappers
  1. Ensure the schema.json is the full Upload File schema with the added owner relation (camelCase). Example attribute to add:
"owner": {
  "type": "relation",
  "relation": "manyToOne",
  "target": "plugin::users-permissions.user"
}

Do not provide a truncated schema. If you omit original fields (e.g. url, hash, mime, etc.), Strapi will treat it as a new content type and break media relations. Always start from the original Upload file schema and append owner.

  1. Rebuild and run Strapi:
rm -rf .cache .tmp
npm run build
npm run dev
  1. In Settings → Users & Permissions → Roles grant the Authenticated role permissions for:

    • POST /upload
    • GET /upload/files
    • GET /upload/files/:id
    • DELETE /upload/files/:id (optional; delete is owner-only at runtime)

    Grant Public role only the endpoints you need (typically GET /upload/files and GET /upload/files/:id if you want public visibility of ownerless files).


Usage

Upload

  • Authenticated upload (Bearer JWT header):
    • The extension sets owner to the current user.
    • The file becomes visible to the owner and to no one else via the protected endpoints.
  • Public upload (if allowed via role):
    • owner stays null and the file is visible to everyone.

Fetch

  • GET /api/upload/files returns:
    • For authenticated users: their files and public files.
    • For unauthenticated users: public files only.
  • GET /api/upload/files/:id returns the file if it’s public or owned by the current user.
  • DELETE /api/upload/files/:id is allowed only to the owner (if role permission is granted).

The extension uses Strapi v5 Document Service to attach ownership and entityService to query with filters on owner.documentId or owner = null.


Implementation Notes

  • The extension avoids setting owner through body.fileInfo because the Upload Content API sanitizes request bodies and rejects unknown keys. Ownership is set after creation using documents('plugin::upload.file').update({ documentId, data: { owner: { connect: [...] }}}).
  • The relation field name must be owner (camelCase). Filters use owner.documentId in Strapi v5.
  • Admin-side audit fields (createdBy, updatedBy) are not used for ownership; they reference Admin users, not Users & Permissions users.

Troubleshooting

  • ValidationError: Invalid key owner
    Ensure your extension schema.json is the full Upload file schema (same collectionName: "files") with the added owner attribute. Rebuild (rm -rf .cache .tmp && npm run build).

  • created_by_id foreign key errors when uploading with JWT users
    Don’t pass opts.user into the Upload service override; admin audit fields point to Admin users and will FK-fail for U&P users.

  • Owner not set after upload
    Confirm the service wrapper runs and that you call documents('plugin::upload.file').update(...) with file.documentId and user.documentId.


License

MIT — use at your own risk.


Links


Keywords / Tags

strapi strapi-v5 strapi-5.23.0 upload upload-plugin content-api ownership file-ownership media authorization access-control users-permissions document-service entity-service extensions security

About

Strapi v5 Upload extension for per-user file ownership and access control (owner-only or public).

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published