@fydemy/cms 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2024-12-06
9
+
10
+ ### Added
11
+
12
+ - Initial stable release of @fydemy/cms
13
+ - File-based CMS for Next.js with markdown support
14
+ - GitHub integration for production deployments
15
+ - Simple authentication with username/password from environment variables
16
+ - TypeScript support with full type definitions
17
+ - Local and GitHub storage providers
18
+ - API handlers for content management (CRUD operations)
19
+ - Authentication middleware for protecting admin routes
20
+ - Session management with JWT
21
+ - File upload functionality
22
+ - Collection and directory listing utilities
23
+
24
+ ### Security
25
+
26
+ - Timing-safe password comparison using `crypto.timingSafeEqual` to prevent timing attacks
27
+ - Rate limiting on login endpoint (5 attempts per 15 minutes)
28
+ - Input validation and sanitization for all user inputs
29
+ - Path validation to prevent directory traversal attacks
30
+ - File size limits (10MB maximum)
31
+ - Frontmatter sanitization to prevent injection attacks
32
+ - Secure session cookies with httpOnly, sameSite, and secure flags
33
+ - Length limits on username (100 chars) and password (1000 chars) inputs
34
+ - Generic error messages to prevent username enumeration
35
+
36
+ ### Documentation
37
+
38
+ - Comprehensive README with installation and usage instructions
39
+ - JSDoc documentation for all public APIs
40
+ - Security policy and vulnerability reporting guidelines
41
+ - MIT License
42
+
43
+ ## [0.1.0] - 2024-12-05
44
+
45
+ ### Added
46
+
47
+ - Initial development release
48
+ - Basic file-based CMS functionality
49
+ - Simple authentication
50
+ - Markdown file operations
@@ -0,0 +1,80 @@
1
+ # @fydemy/cms - Quick Start
2
+
3
+ ## What You Have
4
+
5
+ A complete, minimal CMS package for Next.js:
6
+
7
+ ```
8
+ 📦 @fydemy/cms (packages/core)
9
+ - File-based markdown storage
10
+ - GitHub integration for production
11
+ - Simple auth (env username/password)
12
+ - TypeScript support
13
+
14
+ 🚀 Demo App (apps/dev)
15
+ - Example Next.js application
16
+ - Admin dashboard at /admin
17
+ - Login page, editor, file manager
18
+ ```
19
+
20
+ ## Run the Demo
21
+
22
+ 1. **Copy environment file:**
23
+
24
+ ```bash
25
+ cd apps/dev
26
+ cp .env.local.example .env.local
27
+ ```
28
+
29
+ 2. **Edit `.env.local`** with your credentials:
30
+
31
+ ```env
32
+ CMS_ADMIN_USERNAME=admin
33
+ CMS_ADMIN_PASSWORD=your_password
34
+ CMS_SESSION_SECRET=your-32-char-secret
35
+ ```
36
+
37
+ 3. **Start development server:**
38
+
39
+ ```bash
40
+ cd ../..
41
+ pnpm dev
42
+ ```
43
+
44
+ 4. **Open browser:**
45
+ - Home: http://localhost:3000
46
+ - Admin: http://localhost:3000/admin
47
+ - Login with your credentials
48
+
49
+ ## Use in Your Own Project
50
+
51
+ See [README.md](./README.md) for installation and setup instructions.
52
+
53
+ ## Features
54
+
55
+ - ✅ Create, edit, delete markdown files
56
+ - ✅ Frontmatter support (JSON)
57
+ - ✅ Session-based authentication
58
+ - ✅ Local storage (dev) + GitHub (production)
59
+ - ✅ TypeScript types included
60
+ - ✅ Vercel-compatible
61
+
62
+ ## API Example
63
+
64
+ ```typescript
65
+ import { getMarkdownContent } from "@fydemy/cms";
66
+
67
+ // Read content
68
+ const post = await getMarkdownContent("example.md");
69
+ console.log(post.data.title); // "Example Post"
70
+ console.log(post.content); // markdown content
71
+ ```
72
+
73
+ ## Next Steps
74
+
75
+ 1. Test the admin dashboard locally
76
+ 2. Deploy to Vercel with GitHub token
77
+ 3. Use the utilities in your pages
78
+ 4. Customize the admin UI as needed
79
+
80
+ Built with TypeScript, minimal dependencies, zero database! 🎉
@@ -0,0 +1,329 @@
1
+ # @fydemy/cms
2
+
3
+ [![npm version](https://badge.fury.io/js/@fydemy%2Fcms.svg)](https://www.npmjs.com/package/@fydemy/cms)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)](https://www.typescriptlang.org/)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/)
7
+
8
+ A minimal, secure, file-based CMS for Next.js without database requirements. Store content as markdown files with GitHub integration for production deployments.
9
+
10
+ ## Features
11
+
12
+ - 📝 **File-based Storage** - Markdown files with frontmatter in `/public/content`
13
+ - 🔐 **Secure Authentication** - Timing-safe password comparison, rate limiting, input validation
14
+ - 🚀 **Vercel Compatible** - Deploy without any database setup
15
+ - 🐙 **GitHub Integration** - Automatic file commits in production
16
+ - 📦 **Zero Config** - Minimal setup required
17
+ - 🎯 **TypeScript First** - Full type safety with comprehensive type definitions
18
+ - ⚡ **Lightweight** - Small bundle size (~30KB), minimal dependencies
19
+ - 🛡️ **Security Hardened** - Built with security best practices
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @fydemy/cms
25
+ # or
26
+ pnpm add @fydemy/cms
27
+ # or
28
+ yarn add @fydemy/cms
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ### 1. Initialize the CMS
34
+
35
+ Run the initialization command in your Next.js App Router project:
36
+
37
+ ```bash
38
+ npx fydemy-cms init
39
+ ```
40
+
41
+ This command will automatically:
42
+
43
+ - Create the content directory
44
+ - Scaffold Admin UI pages (`/app/admin`)
45
+ - Create API routes (`/app/api/cms`)
46
+ - Create a `.env.local.example` file
47
+ - Provide instructions for updating `middleware.ts`
48
+
49
+ ### 2. Configure Environment
50
+
51
+ Copy `.env.local.example` to `.env.local` and set your credentials:
52
+
53
+ ```bash
54
+ cp .env.local.example .env.local
55
+ ```
56
+
57
+ Update variables in `.env.local`:
58
+
59
+ ```env
60
+ # Required for authentication
61
+ CMS_ADMIN_USERNAME=admin
62
+ CMS_ADMIN_PASSWORD=your_secure_password
63
+ CMS_SESSION_SECRET=your-secret-key-must-be-at-least-32-characters-long
64
+
65
+ # Optional: For production (GitHub integration)
66
+ GITHUB_TOKEN=ghp_your_github_token
67
+ GITHUB_REPO=username/repository
68
+ GITHUB_BRANCH=main
69
+ ```
70
+
71
+ > **Security Note**: Use strong passwords and keep `CMS_SESSION_SECRET` at least 32 characters long.
72
+
73
+ ### 3. Read Content in Your App
74
+
75
+ ```typescript
76
+ import { getMarkdownContent } from "@fydemy/cms";
77
+
78
+ export default async function BlogPost({
79
+ params,
80
+ }: {
81
+ params: { slug: string };
82
+ }) {
83
+ const post = await getMarkdownContent(`${params.slug}.md`);
84
+
85
+ return (
86
+ <article>
87
+ <h1>{post.data.title}</h1>
88
+ <p>{post.data.description}</p>
89
+ <div>{post.content}</div>
90
+ </article>
91
+ );
92
+ }
93
+ ```
94
+
95
+ ## Security Features
96
+
97
+ ### Built-in Security
98
+
99
+ - **Timing-Safe Authentication**: Uses `crypto.timingSafeEqual` to prevent timing attacks
100
+ - **Rate Limiting**: 5 login attempts per 15 minutes per IP address
101
+ - **Input Validation**: All inputs validated and sanitized
102
+ - **Path Validation**: Prevents directory traversal attacks
103
+ - **File Size Limits**: Default 10MB maximum file size
104
+ - **Secure Sessions**: httpOnly, sameSite, and secure cookies in production
105
+ - **No Username Enumeration**: Generic error messages
106
+
107
+ ### Security Best Practices
108
+
109
+ 1. **Strong Credentials**: Use strong, unique passwords for `CMS_ADMIN_PASSWORD`
110
+ 2. **Secret Management**: Keep `CMS_SESSION_SECRET` at least 32 characters
111
+ 3. **GitHub Token Security**: Use minimal permissions (only `repo` scope)
112
+ 4. **HTTPS Only**: Always use HTTPS in production
113
+ 5. **Regular Updates**: Keep dependencies up to date
114
+ 6. **Environment Variables**: Never commit `.env` files
115
+
116
+ For more security information, see [SECURITY.md](./SECURITY.md).
117
+
118
+ ## API Reference
119
+
120
+ ### Content Management
121
+
122
+ ```typescript
123
+ // Read markdown file
124
+ const content = await getMarkdownContent("blog/post.md");
125
+ // Returns: { data: {...}, content: "..." }
126
+
127
+ // Write markdown file
128
+ await saveMarkdownContent(
129
+ "blog/post.md",
130
+ { title: "My Post", date: "2024-01-01" },
131
+ "# Hello World",
132
+ );
133
+
134
+ // Delete file
135
+ await deleteMarkdownContent("blog/post.md");
136
+
137
+ // List files
138
+ const files = await listMarkdownFiles("blog");
139
+ // Returns: ['blog/post1.md', 'blog/post2.md']
140
+
141
+ // Check if file exists
142
+ const exists = await markdownFileExists("blog/post.md");
143
+ ```
144
+
145
+ ### Parsing Utilities
146
+
147
+ ```typescript
148
+ import { parseMarkdown, stringifyMarkdown } from "@fydemy/cms";
149
+
150
+ // Parse markdown string
151
+ const { data, content } = parseMarkdown(rawMarkdown);
152
+
153
+ // Convert to markdown
154
+ const markdown = stringifyMarkdown({ title: "Post" }, "Content here");
155
+ ```
156
+
157
+ ### Authentication
158
+
159
+ ```typescript
160
+ import { validateCredentials, createSession } from "@fydemy/cms";
161
+
162
+ // Validate credentials
163
+ const isValid = validateCredentials("admin", "password");
164
+
165
+ // Create session (returns JWT)
166
+ const token = await createSession("admin");
167
+ ```
168
+
169
+ ### Validation Utilities
170
+
171
+ ```typescript
172
+ import {
173
+ validateFilePath,
174
+ validateUsername,
175
+ validatePassword,
176
+ sanitizeFrontmatter,
177
+ } from "@fydemy/cms";
178
+
179
+ // Validate file path (prevents directory traversal)
180
+ const safePath = validateFilePath("blog/post.md");
181
+
182
+ // Validate username
183
+ validateUsername("admin"); // throws if invalid
184
+
185
+ // Sanitize frontmatter data
186
+ const safe = sanitizeFrontmatter({ title: "Test", script: "<script>" });
187
+ ```
188
+
189
+ ## Storage
190
+
191
+ ### Development
192
+
193
+ Files are stored locally in `/public/content` directory.
194
+
195
+ ### Production
196
+
197
+ You have two options for production storage:
198
+
199
+ #### Option 1: GitHub Storage (Default)
200
+
201
+ When `NODE_ENV=production` and `GITHUB_TOKEN` is set, all file operations are performed via GitHub API, creating commits directly to your repository.
202
+
203
+ #### Option 2: Cloudflare R2 Storage
204
+
205
+ When Cloudflare R2 credentials are set, files are stored in your R2 bucket. This is ideal for high-traffic sites and provides better performance.
206
+
207
+ See [CLOUDFLARE_R2_SETUP.md](../../CLOUDFLARE_R2_SETUP.md) for detailed setup instructions.
208
+
209
+ ## Environment Variables
210
+
211
+ ### Authentication (Required)
212
+
213
+ | Variable | Required | Description |
214
+ | -------------------- | -------- | ------------------------- |
215
+ | `CMS_ADMIN_USERNAME` | Yes | Admin username |
216
+ | `CMS_ADMIN_PASSWORD` | Yes | Admin password |
217
+ | `CMS_SESSION_SECRET` | Yes | JWT secret (min 32 chars) |
218
+
219
+ ### Storage: GitHub (Optional)
220
+
221
+ | Variable | Required | Description |
222
+ | --------------- | ---------- | ------------------------------- |
223
+ | `GITHUB_TOKEN` | Production | GitHub personal access token |
224
+ | `GITHUB_REPO` | Production | Repository (format: owner/repo) |
225
+ | `GITHUB_BRANCH` | Production | Branch name (default: main) |
226
+
227
+ ### Storage: Cloudflare R2 (Optional)
228
+
229
+ | Variable | Required | Description |
230
+ | ------------------------------ | -------- | -------------------------- |
231
+ | `CLOUDFLARE_ACCOUNT_ID` | Yes | Your Cloudflare Account ID |
232
+ | `CLOUDFLARE_ACCESS_KEY_ID` | Yes | R2 API Access Key ID |
233
+ | `CLOUDFLARE_SECRET_ACCESS_KEY` | Yes | R2 API Secret Access Key |
234
+ | `NEXT_PUBLIC_R2_PUBLIC_URL` | Yes | Public URL for R2 bucket |
235
+ | `R2_BUCKET_NAME` | Yes | Name of your R2 bucket |
236
+
237
+ ## GitHub Setup
238
+
239
+ 1. Create a GitHub Personal Access Token with `repo` permissions
240
+ 2. Add the token to your environment variables
241
+ 3. Deploy to Vercel and configure the environment variables
242
+
243
+ ## Cloudflare R2 Setup
244
+
245
+ 1. Create an R2 bucket in your Cloudflare dashboard
246
+ 2. Generate API tokens with read/write permissions
247
+ 3. Configure your bucket's public access settings
248
+ 4. Add the credentials to your environment variables
249
+
250
+ For detailed instructions, see [CLOUDFLARE_R2_SETUP.md](../../CLOUDFLARE_R2_SETUP.md).
251
+
252
+ ## FAQ
253
+
254
+ ### Is this suitable for production?
255
+
256
+ Yes! The package includes security hardening, rate limiting, and has been tested for production use. Make sure to follow security best practices.
257
+
258
+ ### Can I use this with other frameworks?
259
+
260
+ This package is designed for Next.js App Router (13+). For other frameworks, you can use the core utilities but will need to implement your own API routes.
261
+
262
+ ### How do I customize the file size limit?
263
+
264
+ ```typescript
265
+ import { MAX_FILE_SIZE } from "@fydemy/cms";
266
+ // Default is 10MB, you can check this constant
267
+ ```
268
+
269
+ To change it, you'll need to implement your own validation layer.
270
+
271
+ ### Does it support images?
272
+
273
+ Yes! The package includes file upload functionality. Images can be uploaded and stored in `/public/uploads` (local) or via GitHub API (production).
274
+
275
+ ### How do I backup my content?
276
+
277
+ Since content is stored in your GitHub repository (in production), it's automatically backed up with full version history. In development, the `/public/content` directory can be committed to git.
278
+
279
+ ### What about rate limiting in production?
280
+
281
+ The built-in rate limiter is memory-based and resets on server restart. For production with multiple instances, consider implementing Redis-based rate limiting.
282
+
283
+ ### Can I add more admin users?
284
+
285
+ Currently, the package supports a single admin user via environment variables. For multi-user support, you'd need to implement a custom authentication layer.
286
+
287
+ ## Example Admin UI
288
+
289
+ Check the `/apps/dev` directory in this repository for a complete example with:
290
+
291
+ - Login page
292
+ - Admin dashboard
293
+ - File editor
294
+ - File management
295
+
296
+ ## Troubleshooting
297
+
298
+ ### "CMS_SESSION_SECRET must be at least 32 characters"
299
+
300
+ Make sure your session secret is long enough. Generate a secure random string:
301
+
302
+ ```bash
303
+ node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
304
+ ```
305
+
306
+ ### Rate limiting not working across restarts
307
+
308
+ The rate limiter is in-memory. For persistent rate limiting, implement Redis storage.
309
+
310
+ ### GitHub API rate limits
311
+
312
+ GitHub API has rate limits. For high-traffic sites, consider caching content or using a CDN.
313
+
314
+ ## License
315
+
316
+ MIT
317
+
318
+ ## Contributing
319
+
320
+ Contributions welcome! This is a minimal CMS focused on simplicity and maintainability.
321
+
322
+ Please report security vulnerabilities privately to fydemy@gmail.com or via GitHub security advisories.
323
+
324
+ ## Links
325
+
326
+ - [GitHub Repository](https://github.com/fydemy/cms)
327
+ - [npm Package](https://www.npmjs.com/package/@fydemy/cms)
328
+ - [Report Issues](https://github.com/fydemy/cms/issues)
329
+ - [Security Policy](https://github.com/fydemy/cms/blob/main/SECURITY.md)
@@ -0,0 +1,79 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ We release patches for security vulnerabilities for the following versions:
6
+
7
+ | Version | Supported |
8
+ | ------- | ------------------ |
9
+ | 1.x.x | :white_check_mark: |
10
+ | < 1.0 | :x: |
11
+
12
+ ## Reporting a Vulnerability
13
+
14
+ **Please do not report security vulnerabilities through public GitHub issues.**
15
+
16
+ If you discover a security vulnerability in @fydemy/cms, please report it by emailing fydemy@gmail.com (or create a private security advisory on GitHub).
17
+
18
+ Please include the following information:
19
+
20
+ - Type of vulnerability
21
+ - Full paths of source file(s) related to the vulnerability
22
+ - Location of the affected source code (tag/branch/commit or direct URL)
23
+ - Step-by-step instructions to reproduce the issue
24
+ - Proof-of-concept or exploit code (if possible)
25
+ - Impact of the issue, including how an attacker might exploit it
26
+
27
+ We will acknowledge your email within 48 hours and send a more detailed response within 7 days indicating the next steps in handling your report.
28
+
29
+ ## Security Best Practices
30
+
31
+ When using @fydemy/cms, follow these security best practices:
32
+
33
+ ### Environment Variables
34
+
35
+ - Use strong, random values for `CMS_SESSION_SECRET` (minimum 32 characters)
36
+ - Use strong passwords for `CMS_ADMIN_PASSWORD`
37
+ - Never commit `.env` files to version control
38
+ - Rotate credentials regularly
39
+
40
+ ### GitHub Token
41
+
42
+ - Use GitHub Personal Access Tokens with minimal required permissions (only `repo` scope)
43
+ - Use fine-grained personal access tokens when possible
44
+ - Store tokens securely in your deployment platform's secret management
45
+
46
+ ### Network Security
47
+
48
+ - Always use HTTPS in production
49
+ - Configure your Next.js app behind a reverse proxy or CDN
50
+ - Enable security headers (CSP, HSTS, X-Frame-Options, etc.)
51
+
52
+ ### Rate Limiting
53
+
54
+ - The built-in rate limiter is memory-based and resets on server restart
55
+ - For production, consider implementing Redis-based rate limiting
56
+ - Monitor failed login attempts
57
+
58
+ ### File Uploads
59
+
60
+ - The default file size limit is 10MB
61
+ - Validate file types on the client and server
62
+ - Consider implementing virus scanning for uploaded files
63
+ - Use Content Security Policy headers to prevent XSS from uploaded content
64
+
65
+ ### Session Security
66
+
67
+ - Session cookies are httpOnly, sameSite=lax, and secure in production
68
+ - Sessions expire after 7 days
69
+ - Consider shorter session duration for sensitive applications
70
+
71
+ ## Disclosure Policy
72
+
73
+ When we receive a security bug report, we will:
74
+
75
+ 1. Confirm the problem and determine affected versions
76
+ 2. Audit code to find similar problems
77
+ 3. Prepare fixes for all supported versions
78
+ 4. Release new versions as soon as possible
79
+ 5. Credit the reporter (unless they prefer to remain anonymous)