Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions skills/firebase-storage-basics/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
name: firebase-storage-basics
description: Comprehensive guide for Firebase Storage basics including provisioning, security rules, and SDK usage. Use this skill when the user needs help setting up Cloud Storage for Firebase, writing security rules, or using the Cloud Storage for Firebase SDK in their application.
---

# Firebase Storage Basics

This skill provides a complete guide for getting started with Cloud Storage for Firebase, including provisioning, securing, and integrating it into your application.

## Provisioning

To set up Cloud Storage in your Firebase project and local environment, see [provisioning.md](references/provisioning.md).

**Important**: In order to use Cloud Storage, your Firebase project must be on the Blaze pricing plan. Direct the user to https://console.firebase.google.com/project/_/overview?purchaseBillingPlan=metered to upgrade their plan.

## Security Rules

For guidance on writing and deploying Storage Security Rules to protect your files, see [security_rules.md](references/security_rules.md).

## SDK Usage

To learn how to use Cloud Storage in your application code, see:

* **Web (Modular SDK)**: [web_sdk_usage.md](references/web_sdk_usage.md)
51 changes: 51 additions & 0 deletions skills/firebase-storage-basics/references/provisioning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Provisioning Cloud Storage for Firebase

## 1. Enable Storage in the Firebase Console

Before you can use Cloud Storage, you need to enable it in your Firebase project:

1. Go to the [Firebase Console](https://console.firebase.google.com/).
2. Select your project.
3. Navigate to **Build > Storage** in the left sidebar.
4. Click **Get started**.
5. Review the default security rules (you can start in **Test mode** for development, but remember to secure them later).
6. Select a location for your default Cloud Storage bucket. **Note:** This location cannot be changed later.
7. Click **Done**.

## 2. Manual Project Configuration

Instead of using the interactive `firebase init` command, you should manually configure your project by creating or updating the following files in your project root. This ensures a deterministic setup suitable for automation.

### Create `storage.rules`

Create a file named `storage.rules` in your project root. Here is a basic secure starting point that requires authentication for all access:

```javascript
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
```

### Update `firebase.json`

Add the `storage` configuration to your `firebase.json` file. If the file doesn't exist, create it. This tells the Firebase CLI which rules file to use for deployment.

```json
{
"storage": {
"rules": "storage.rules"
}
}
```

## 3. Verify and Deploy

To verify your configuration and deploy your Storage rules to the Firebase backend:

```bash
firebase deploy --only storage
```
88 changes: 88 additions & 0 deletions skills/firebase-storage-basics/references/security_rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Firebase Storage Security Rules

Firebase Security Rules for Cloud Storage determine who has read and write access to files stored in Cloud Storage, as well as how files are structured and what metadata they contain.

## Basic Structure

Storage rules are defined in a `service firebase.storage` block. Match statements point to specific file paths.

```javascript
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
```

* `match /b/{bucket}/o`: This is the required entry point for all Storage rules.
* `match /{allPaths=**}`: Matches all files in the bucket.
* `allow read, write`: Grants permission.

## Granular Access Control

You can write rules for specific paths to control access more granularly:

```javascript
service firebase.storage {
match /b/{bucket}/o {
// User profile images: Publicly readable, writable only by the user
match /users/{userId}/profile.jpg {
allow read: if true;
allow write: if request.auth != null && request.auth.uid == userId;
}

// Private user files: Only accessible by the user
match /users/{userId}/private/{fileName} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
```

## Validating File Metadata

You can also validate file properties like size and content type:

```javascript
allow write: if request.resource.size < 5 * 1024 * 1024 // 5MB
&& request.resource.contentType.matches('image/.*');
```

## Workflow for Secure Rules

To ensure your rules are robust, follow this workflow:

### 1. Analyze Requirements
Identify:
* **Paths**: What files are you storing? (e.g., `/users/{uid}/avatar.png`)
* **Access**: Who can read/write? (e.g., Public read, Owner write)
* **Constraints**: Max size? Specific content types?

### 2. Draft Rules
Start with **Default Deny** and open up permissions only as needed.

### 3. "Devil's Advocate" Attack (Critical Step)
Attempt to break your own rules mentally or via tests:
1. **Unauthorized Access**: Can user A read user B's private file?
2. **Path Traversal**: Can I write to a path not explicitly defined?
3. **Validation Bypass**: Can I upload a 1GB file if the limit is 5MB? Can I upload an `.exe` instead of `.jpg`?
4. **Unauthenticated Access**: What happens if `request.auth` is null?

### 4. Automated Testing
Use the Firebase Emulator and `@firebase/rules-unit-testing` to write unit tests for your rules.

**Example Test Plan:**
* Authorized upload (should succeed)
* Unauthorized upload (should fail)
* File size limit check (should fail if too large)
* Wrong file type (should fail)
* Public read (should succeed)
* Private read (unauthorized user should fail)

## Deploying Rules

```bash
firebase deploy --only storage
```
109 changes: 109 additions & 0 deletions skills/firebase-storage-basics/references/web_sdk_usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Cloud Storage for Firebase - Web SDK Usage

This guide covers the basics of using Cloud Storage in a web application using the modular SDK (v9+).

## 1. Initialize Storage

Ensure you have initialized your Firebase app first.

```javascript
import { initializeApp } from "firebase/app";
import { getStorage } from "firebase/storage";

// If running in Firebase App Hosting, you can skip Firebase Config and instead use:
// const app = initializeApp();

const firebaseConfig = {
// Your Firebase app config object. Get this by running 'firebase apps:sdkconfig [options] web [appId]
};

const app = initializeApp(firebaseConfig);
const storage = getStorage(app);
```

## 2. Create a Reference

A reference points to a file or location in your bucket.

```javascript
import { ref } from "firebase/storage";

// Create a child reference
const imagesRef = ref(storage, 'images');

// References can be chained
const spaceRef = ref(storage, 'images/space.jpg');
// OR
const spaceRef2 = ref(imagesRef, 'space.jpg');
```

## 3. Upload a File

Use `uploadBytes` for simple uploads or `uploadBytesResumable` for monitoring progress.

```javascript
import { ref, uploadBytes } from "firebase/storage";

const storageRef = ref(storage, 'some-child');
const file = ... // File object from input element

uploadBytes(storageRef, file).then((snapshot) => {
console.log('Uploaded a blob or file!');
});
```

### With Metadata

```javascript
const metadata = {
contentType: 'image/jpeg',
customMetadata: {
'uploadedBy': 'user123'
}
};

uploadBytes(storageRef, file, metadata).then((snapshot) => {
console.log('Uploaded with metadata');
});
```

## 4. Download a File (Get URL)

To display an image or create a download link, get the download URL.

```javascript
import { ref, getDownloadURL } from "firebase/storage";

getDownloadURL(ref(storage, 'images/stars.jpg'))
.then((url) => {
// Insert url into an <img> tag to "download"
const img = document.getElementById('myimg');
img.setAttribute('src', url);
})
.catch((error) => {
// Handle any errors
});
```

## 5. Handling Errors

Always handle errors (e.g., user canceled, permission denied).

```javascript
.catch((error) => {
switch (error.code) {
case 'storage/object-not-found':
// File doesn't exist
break;
case 'storage/unauthorized':
// User doesn't have permission to access the object
break;
case 'storage/canceled':
// User canceled the upload
break;
case 'storage/unknown':
// Unknown error occurred
break;
}
});
```