Token导航 LogoToken导航TokenDH.com
前端设计需要联网github未标认证来源可访问许可证需确认审计异常

file-uploads文件上传

Agent Skill

file-uploads 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

654

周安装

27

GitHub Stars

777

下载量

214
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:file-uploads(文件上传)
来源仓库:https://github.com/dadbodgeoff/drift
仓库路径:skills/file-uploads
安装命令:
npx skills add https://github.com/dadbodgeoff/drift --skill file-uploads
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/dadbodgeoff/drift --skill file-uploads

简介

file-uploads 用于安全处理用户上传与恶意扫描,适合在 Codex、Claude、Cursor、Gemini CLI 中需要防范攻击向量或去重处理时使用。

  • 它采用多阶段校验管道:大小类型检查、内容签名与 ClamAV 扫描,支持并发上传识别。
  • 使用时需限制文件类型与大小,启用服务端验证;建议隔离处理环境与自动清理临时文件。
  • 安装前请核实权限边界,注意是否会执行外部进程或写入磁盘,确保符合数据保留策略。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

Secure Upload Pipeline

Production-grade file upload handling with validation, malware scanning, and duplicate detection.

When to Use This Skill

  • Building file upload endpoints that handle untrusted input
  • Need malware scanning before processing files
  • Want to prevent duplicate file processing
  • Handling concurrent uploads of the same file

Core Concepts

File uploads are attack vectors. The solution is a multi-stage validation pipeline that fails fast and checks cheap things first:

Upload Request
    ↓
[1] Size + Type Check (instant)
    ↓
[2] Content Signature Validation (ms)
    ↓
[3] Malware Scan - ClamAV (50-200ms)
    ↓
[4] Hash-Based Duplicate Check (ms)
    ↓
[5] Race Condition Lock (Redis)
    ↓
[6] Upload to Storage
    ↓
[7] Clear Lock + Return URL

Key principle: Check limits BEFORE upload to prevent wasted processing.

Implementation

Python (FastAPI)

import hashlib
from typing import Optional, Dict
from fastapi import UploadFile, HTTPException

class FileValidator:
    def __init__(self):
        self.max_size = 10 * 1024 * 1024  # 10MB
        self.allowed_types = ['application/pdf', 'image/jpeg', 'image/png']
        self.malware_scanner = MalwareScannerService()

    async def validate_file(self, file: UploadFile) -> Dict:
        """Multi-stage file validation"""
        validation_details = {
            "filename": file.filename,
            "content_type": file.content_type,
            "checks_passed": []
        }

        # Check 1: File size (before reading content)
        file.file.seek(0, 2)
        file_size = file.file.tell()
        file.file.seek(0)

        if file_size > self.max_size:
            return {
                "valid": False,
                "error": f"File too large ({file_size / 1024 / 1024:.1f}MB). Max 10MB.",
                "validation_details": validation_details
            }

        if file_size == 0:
            return {"valid": False, "error": "File is empty."}

        validation_details["checks_passed"].append("size_check")

        # Check 2: MIME type
        if file.content_type not in self.allowed_types:
            return {
                "valid": False,
                "error": f"Invalid file type ({file.content_type})."
            }

        validation_details["checks_passed"].append("type_check")

        # Check 3: Content signature (PDF magic bytes)
        if file.content_type == 'application/pdf':
            header = await file.read(4)
            file.file.seek(0)

            if header != b'%PDF':
                return {"valid": False, "error": "File appears corrupted."}

            validation_details["checks_passed"].append("pdf_signature_check")

        # Check 4: Malware scan
        scan_result = await self.malware_scanner.scan_file(file)

        if not scan_result['safe']:
            return {
                "valid": False,
                "error": f"Security threat detected: {scan_result.get('threat_found')}"
            }

        validation_details["checks_passed"].append("malware_scan")

        return {"valid": True, "error": None, "validation_details": validation_details}

class MalwareScannerService:
    """ClamAV integration with graceful degradation"""

    def __init__(self):
        self.enabled = os.getenv('CLAMAV_ENABLED', 'true').lower() == 'true'
        self.client = None

        if self.enabled:
            try:
                import clamd
                self.client = clamd.ClamdNetworkSocket(
                    host=os.getenv('CLAMAV_HOST', 'localhost'),
                    port=int(os.getenv('CLAMAV_PORT', '3310'))
                )
                self.client.ping()
            except Exception as e:
                logger.warning(f"ClamAV not available: {e}")
                self.enabled = False

    async def scan_file(self, file: UploadFile) -> Dict:
        if not self.enabled or not self.client:
            return {"safe": True, "scan_performed": False}

        try:
            from io import BytesIO
            file_content = await file.read()
            file.file.seek(0)

            result = self.client.instream(BytesIO(file_content))
            status, threat = result.get('stream', ('ERROR', 'Unknown'))

            if status == 'OK':
                return {"safe": True, "scan_performed": True}
            elif status == 'FOUND':
                logger.warning(f"MALWARE: {file.filename} - {threat}")
                return {"safe": False, "threat_found": threat, "scan_performed": True}
            else:
                return {"safe": False, "threat_found": f"Scan error: {status}"}

        except Exception as e:
            # Fail-safe: reject if scan fails
            return {"safe": False, "threat_found": f"Scan failed: {str(e)}"}

class DuplicateDetector:
    """Hash-based duplicate detection with race protection"""

    def calculate_file_hash(self, file_content: bytes) -> str:
        return hashlib.sha256(file_content).hexdigest()

    async def check_duplicate(self, account_id: str, file_hash: str) -> Optional[Dict]:
        result = self.client.table("files").select("id").eq(
            "account_id", account_id
        ).eq("file_hash", file_hash).execute()

        if result.data:
            return {"type": "file_hash", "message": "Exact duplicate detected"}
        return None

    async def mark_processing(self, account_id: str, file_hash: str, ttl: int = 300):
        """Mark file as being processed (prevents concurrent processing)"""
        key = f"processing:{account_id}:{file_hash}"
        self.redis.setex(key, ttl, "1")

    async def is_processing(self, account_id: str, file_hash: str) -> bool:
        key = f"processing:{account_id}:{file_hash}"
        return self.redis.exists(key) > 0

    async def clear_processing(self, account_id: str, file_hash: str):
        key = f"processing:{account_id}:{file_hash}"
        self.redis.delete(key)

TypeScript

import { createHash } from 'crypto';

interface ValidationResult {
  valid: boolean;
  error?: string;
  checksPassed: string[];
}

class FileValidator {
  private maxSize = 10 * 1024 * 1024; // 10MB
  private allowedTypes = ['application/pdf', 'image/jpeg', 'image/png'];

  async validate(file: File): Promise<ValidationResult> {
    const checksPassed: string[] = [];

    // Check 1: Size
    if (file.size > this.maxSize) {
      return { valid: false, error: 'File too large', checksPassed };
    }
    if (file.size === 0) {
      return { valid: false, error: 'File is empty', checksPassed };
    }
    checksPassed.push('size_check');

    // Check 2: MIME type
    if (!this.allowedTypes.includes(file.type)) {
      return { valid: false, error: 'Invalid file type', checksPassed };
    }
    checksPassed.push('type_check');

    // Check 3: Content signature
    if (file.type === 'application/pdf') {
      const header = await this.readHeader(file, 4);
      if (header !== '%PDF') {
        return { valid: false, error: 'File appears corrupted', checksPassed };
      }
      checksPassed.push('pdf_signature_check');
    }

    return { valid: true, checksPassed };
  }

  private async readHeader(file: File, bytes: number): Promise<string> {
    const slice = file.slice(0, bytes);
    const buffer = await slice.arrayBuffer();
    return new TextDecoder().decode(buffer);
  }
}

class DuplicateDetector {
  async calculateHash(file: File): Promise<string> {
    const buffer = await file.arrayBuffer();
    const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
    return Array.from(new Uint8Array(hashBuffer))
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }
}

Usage Examples

Complete Upload Endpoint

@router.post("/upload")
async def upload_file(
    file: UploadFile = File(...),
    auth: AuthenticatedUser = Depends(get_current_user),
):
    # Check limits FIRST
    allowed, details = usage_service.check_limit(auth.id, 'file_upload')
    if not allowed:
        raise HTTPException(status_code=429, detail=details)

    # Stage 1-3: Validate
    validation = await file_validator.validate_file(file)
    if not validation['valid']:
        raise HTTPException(status_code=400, detail=validation['error'])

    # Stage 4: Hash for duplicate detection
    file.file.seek(0)
    file_content = await file.read()
    file_hash = duplicate_detector.calculate_file_hash(file_content)
    file.file.seek(0)

    # Check duplicate
    duplicate = await duplicate_detector.check_duplicate(auth.account_id, file_hash)
    if duplicate:
        raise HTTPException(status_code=409, detail=duplicate)

    # Stage 5: Race protection
    if await duplicate_detector.is_processing(auth.account_id, file_hash):
        raise HTTPException(status_code=409, detail="File is being processed")

    await duplicate_detector.mark_processing(auth.account_id, file_hash, ttl=300)

    try:
        # Stage 6: Upload
        file_url = await storage_service.upload_file(file, auth.id)
    finally:
        # Stage 7: Clear lock
        await duplicate_detector.clear_processing(auth.account_id, file_hash)

    return {"success": True, "file_url": file_url, "file_hash": file_hash}

Best Practices

  1. Check limits BEFORE upload - Don't waste bandwidth on files that will be rejected
  2. TTL on processing markers - If upload crashes, marker auto-expires (300s default)
  3. ClamAV graceful degradation - Don't block uploads if scanner is down
  4. Hash before upload - Calculate hash from memory, not after storage write
  5. Fail-safe on scan errors - Reject file if malware scan fails

Common Mistakes

  • Processing files before checking usage limits
  • No TTL on processing markers (stuck forever if crash)
  • Blocking uploads when ClamAV is unavailable
  • Calculating hash after storage write (wasted upload)
  • Allowing uploads when malware scan fails

Related Patterns

  • rate-limiting - Rate limit upload endpoints
  • distributed-lock - Coordinate concurrent uploads
  • validation-quarantine - Quarantine suspicious files

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.68%
按下载量换算74

Claude

29.24%
按下载量换算63

Cursor

19.79%
按下载量换算42

Gemini CLI

8.96%
按下载量换算19

安全审计

Gen Agent Trust Hub

未通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills