MCPcopy
hub / github.com/simstudioai/sim / verifyPublicAssetWriteAccess

Function verifyPublicAssetWriteAccess

apps/sim/app/api/files/authorization.ts:287–345  ·  view source on GitHub ↗

* Authorize a destructive operation (delete) on a "public" asset context: * `profile-pictures`, `workspace-logos`, or `og-images`. These contexts are * world-readable, so verifyFileAccess short-circuits reads — but a write * must prove ownership of the user/workspace the object belongs to

(
  cloudKey: string,
  userId: string,
  context: 'profile-pictures' | 'og-images' | 'workspace-logos',
  customConfig?: StorageConfig
)

Source from the content-addressed store, hash-verified

285 * and no user-facing delete path; always deny.
286 */
287async function verifyPublicAssetWriteAccess(
288 cloudKey: string,
289 userId: string,
290 context: 'profile-pictures' | 'og-images' | 'workspace-logos',
291 customConfig?: StorageConfig
292): Promise<boolean> {
293 try {
294 if (context === 'workspace-logos') {
295 const binding = await getFileMetadataByKey(cloudKey, 'workspace-logos')
296 if (!binding?.workspaceId) {
297 logger.warn('workspace-logos delete denied: no ownership binding', { userId, cloudKey })
298 return false
299 }
300 const permission = await getUserEntityPermissions(userId, 'workspace', binding.workspaceId)
301 if (!workspacePermissionSatisfies(permission, true)) {
302 logger.warn('workspace-logos delete denied: write/admin required on owner workspace', {
303 userId,
304 workspaceId: binding.workspaceId,
305 cloudKey,
306 })
307 return false
308 }
309 return true
310 }
311
312 if (context === 'profile-pictures') {
313 const config: StorageConfig = customConfig || {}
314 const metadata = await getFileMetadata(cloudKey, config)
315 if (metadata.userId && metadata.userId === userId) {
316 return true
317 }
318 // Fail closed when the owner cannot be established. Distinguish a missing
319 // owner record (no `userId` metadata — e.g. an object predating owner
320 // tagging) from a genuine ownership mismatch so the denial is diagnosable.
321 if (!metadata.userId) {
322 logger.warn(
323 'profile-pictures delete denied: file has no owner metadata to verify against',
324 {
325 userId,
326 cloudKey,
327 }
328 )
329 } else {
330 logger.warn('profile-pictures delete denied: caller does not own the file', {
331 userId,
332 fileUserId: metadata.userId,
333 cloudKey,
334 })
335 }
336 return false
337 }
338
339 logger.warn('og-images delete denied: no user-facing delete path', { userId, cloudKey })
340 return false
341 } catch (error) {
342 logger.error('Error verifying public asset write access', { cloudKey, userId, error })
343 return false
344 }

Callers 1

verifyFileAccessFunction · 0.85

Calls 6

getFileMetadataByKeyFunction · 0.90
getUserEntityPermissionsFunction · 0.90
getFileMetadataFunction · 0.90
errorMethod · 0.80
warnMethod · 0.65

Tested by

no test coverage detected