From 1e06e2bd4b7e034ed43187817fbdbb07865da3b3 Mon Sep 17 00:00:00 2001 From: Arunavo Ray Date: Sat, 19 Jul 2025 00:28:12 +0530 Subject: [PATCH] Remove Auto Migrate --- README.md | 4 +- UPGRADE.md | 74 +++++++++++++++ docker-entrypoint.sh | 77 +-------------- package.json | 2 - scripts/migrate-better-auth.ts | 100 -------------------- scripts/migrate-to-better-auth.ts | 87 ----------------- scripts/migrate-tokens-encryption.ts | 135 --------------------------- 7 files changed, 77 insertions(+), 402 deletions(-) create mode 100644 UPGRADE.md delete mode 100644 scripts/migrate-better-auth.ts delete mode 100644 scripts/migrate-to-better-auth.ts delete mode 100644 scripts/migrate-tokens-encryption.ts diff --git a/README.md b/README.md index e0916d5..cb92fda 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@

> [!IMPORTANT] -> **Upgrading to v3?** Please read the [Migration Guide](MIGRATION_GUIDE.md) for breaking changes and upgrade instructions. +> **Upgrading to v3?** v3 requires a fresh start with a new data volume. Please read the [Upgrade Guide](UPGRADE.md) for instructions. ## šŸš€ Quick Start @@ -35,7 +35,7 @@ First user signup becomes admin. Configure GitHub and Gitea through the web inte - šŸ” Mirror public, private, and starred GitHub repos to Gitea - šŸ¢ Mirror entire organizations with flexible strategies - šŸŽÆ Custom destination control for repos and organizations -- šŸ” Secure authentication with JWT tokens +- šŸ” Secure authentication with Better Auth (email/password, SSO, OIDC) - šŸ“Š Real-time dashboard with activity logs - ā±ļø Scheduled automatic mirroring - 🐳 Dockerized with multi-arch support (AMD64/ARM64) diff --git a/UPGRADE.md b/UPGRADE.md new file mode 100644 index 0000000..a08df45 --- /dev/null +++ b/UPGRADE.md @@ -0,0 +1,74 @@ +# Upgrade Guide + +## Upgrading to v3.0 + +> **āš ļø IMPORTANT**: v3.0 requires a fresh start. There is no automated migration from v2.x to v3.0. + +### Why No Migration? + +v3.0 introduces fundamental changes to the application architecture: +- **Authentication**: Switched from JWT to Better Auth +- **Database**: Now uses Drizzle ORM with proper migrations +- **Security**: All tokens are now encrypted +- **Features**: Added SSO support and OIDC provider functionality + +Due to these extensive changes, we recommend starting fresh with v3.0 for the best experience. + +### Upgrade Steps + +1. **Stop your v2.x container** + ```bash + docker stop gitea-mirror + docker rm gitea-mirror + ``` + +2. **Backup your v2.x data (optional)** + ```bash + # If you want to keep your v2 data for reference + docker run --rm -v gitea-mirror-data:/data -v $(pwd):/backup alpine tar czf /backup/gitea-mirror-v2-backup.tar.gz -C /data . + ``` + +3. **Create a new volume for v3** + ```bash + docker volume create gitea-mirror-v3-data + ``` + +4. **Run v3 with the new volume** + ```bash + docker run -d \ + --name gitea-mirror \ + -p 4321:4321 \ + -v gitea-mirror-v3-data:/app/data \ + -e BETTER_AUTH_SECRET=your-secret-key \ + -e ENCRYPTION_SECRET=your-encryption-key \ + arunavo4/gitea-mirror:latest + ``` + +5. **Set up your configuration again** + - Navigate to http://localhost:4321 + - Create a new admin account + - Re-enter your GitHub and Gitea credentials + - Configure your mirror settings + +### What Happens to My Existing Mirrors? + +Your existing mirrors in Gitea are **not affected**. The application will: +- Recognize existing repositories when you re-import +- Skip creating duplicates +- Resume normal mirror operations + +### Environment Variable Changes + +v3.0 uses different environment variables: + +| v2.x | v3.0 | Notes | +|------|------|-------| +| `JWT_SECRET` | `BETTER_AUTH_SECRET` | Required for session management | +| - | `ENCRYPTION_SECRET` | New - required for token encryption | + +### Need Help? + +If you have questions about upgrading: +1. Check the [README](README.md) for v3 setup instructions +2. Review your v2 configuration before upgrading +3. Open an issue if you encounter problems \ No newline at end of file diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index c010719..6015c11 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -269,82 +269,7 @@ else bun scripts/manage-db.ts fix fi - # Run database migrations - echo "Running database migrations..." - - # Update mirror_jobs table with new columns for resilience - if [ -f "dist/scripts/update-mirror-jobs-table.js" ]; then - echo "Updating mirror_jobs table..." - bun dist/scripts/update-mirror-jobs-table.js - elif [ -f "scripts/update-mirror-jobs-table.ts" ]; then - echo "Updating mirror_jobs table using TypeScript script..." - bun scripts/update-mirror-jobs-table.ts - else - echo "Warning: Could not find mirror_jobs table update script." - fi - - # Run v3 migrations if needed - echo "Checking for v3 migrations..." - - # Check if we need to run Better Auth migration (check if accounts table exists) - if ! sqlite3 /app/data/gitea-mirror.db "SELECT name FROM sqlite_master WHERE type='table' AND name='accounts';" | grep -q accounts; then - echo "šŸ”„ v3 Migration: Creating Better Auth tables..." - # Create Better Auth tables - sqlite3 /app/data/gitea-mirror.db < 0) { - console.log("āœ“ Better Auth migration already completed"); - return; - } - - // Check if we have old users table with passwords - // This query checks if password column exists in users table - const hasPasswordColumn = await db.get<{ count: number }>( - sql`SELECT COUNT(*) as count FROM pragma_table_info('users') WHERE name = 'password'` - ); - - if (!hasPasswordColumn || hasPasswordColumn.count === 0) { - console.log("ā„¹ļø Users table doesn't have password column - migration may have already been done"); - - // Check if we have any users without accounts - const usersWithoutAccounts = await db.all<{ id: string; email: string }>( - sql`SELECT u.id, u.email FROM users u LEFT JOIN accounts a ON u.id = a.user_id WHERE a.id IS NULL` - ); - - if (usersWithoutAccounts.length === 0) { - console.log("āœ“ All users have accounts - migration complete"); - return; - } - - console.log(`āš ļø Found ${usersWithoutAccounts.length} users without accounts - they may need to reset passwords`); - return; - } - - // Get all users with password hashes using raw SQL since the schema doesn't have password - const allUsersWithPasswords = await db.all<{ id: string; email: string; username: string; password: string }>( - sql`SELECT id, email, username, password FROM users WHERE password IS NOT NULL` - ); - - if (allUsersWithPasswords.length === 0) { - console.log("ā„¹ļø No users with passwords to migrate"); - return; - } - - console.log(`šŸ“Š Found ${allUsersWithPasswords.length} users to migrate`); - - // Migrate each user - for (const user of allUsersWithPasswords) { - try { - // Create Better Auth account entry - await db.insert(accounts).values({ - id: crypto.randomUUID(), - userId: user.id, - accountId: user.email, // Use email as account ID - providerId: "credential", // Better Auth credential provider - providerUserId: null, - accessToken: null, - refreshToken: null, - expiresAt: null, - password: user.password, // Move password hash to accounts table - createdAt: new Date(), - updatedAt: new Date() - }); - - console.log(`āœ“ Migrated user: ${user.email}`); - } catch (error) { - console.error(`āŒ Failed to migrate user ${user.email}:`, error); - // Continue with other users even if one fails - } - } - - // Remove password column from users table if it exists - console.log("šŸ”„ Cleaning up old password column..."); - try { - // SQLite doesn't support DROP COLUMN directly, so we need to recreate the table - // For now, we'll just leave it as is since it's not harmful - console.log("ā„¹ļø Password column left in users table for compatibility"); - } catch (error) { - console.error("āš ļø Could not remove password column:", error); - } - - console.log("āœ… Better Auth migration completed successfully"); - - // Verify migration - const migratedAccounts = await db.select().from(accounts); - console.log(`šŸ“Š Total accounts after migration: ${migratedAccounts.length}`); - - } catch (error) { - console.error("āŒ Better Auth migration failed:", error); - process.exit(1); - } -} - -// Run migration -migrateToBetterAuth(); \ No newline at end of file diff --git a/scripts/migrate-to-better-auth.ts b/scripts/migrate-to-better-auth.ts deleted file mode 100644 index 9790021..0000000 --- a/scripts/migrate-to-better-auth.ts +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env bun - -import { db, users, accounts } from "../src/lib/db"; -import { eq } from "drizzle-orm"; -import { v4 as uuidv4 } from "uuid"; - -/** - * Migrate existing users to Better Auth schema - * - * This script: - * 1. Moves existing password hashes from users table to accounts table - * 2. Updates user data to match Better Auth requirements - * 3. Creates credential accounts for existing users - */ - -async function migrateUsers() { - console.log("šŸ”„ Starting user migration to Better Auth..."); - - try { - // Get all existing users - const existingUsers = await db.select().from(users); - - if (existingUsers.length === 0) { - console.log("āœ… No users to migrate"); - return; - } - - console.log(`Found ${existingUsers.length} users to migrate`); - - for (const user of existingUsers) { - console.log(`\nMigrating user: ${user.username} (${user.email})`); - - // Check if user already has a credential account - const existingAccount = await db - .select() - .from(accounts) - .where( - eq(accounts.userId, user.id) && - eq(accounts.providerId, "credential") - ) - .limit(1); - - if (existingAccount.length > 0) { - console.log("āœ“ User already migrated"); - continue; - } - - // Create credential account with existing password hash - const accountId = uuidv4(); - await db.insert(accounts).values({ - id: accountId, - accountId: accountId, - userId: user.id, - providerId: "credential", - providerUserId: user.email, // Use email as provider user ID - // password: user.password, // Password is not in users table anymore - createdAt: user.createdAt, - updatedAt: user.updatedAt, - }); - - console.log("āœ“ Created credential account"); - - // Update user name field if it's null (Better Auth uses 'name' field) - // Note: Better Auth expects a 'name' field, but we're using username - // This is handled by our additional fields configuration - } - - console.log("\nāœ… User migration completed successfully!"); - - // Summary - const migratedAccounts = await db - .select() - .from(accounts) - .where(eq(accounts.providerId, "credential")); - - console.log(`\nMigration Summary:`); - console.log(`- Total users: ${existingUsers.length}`); - console.log(`- Migrated accounts: ${migratedAccounts.length}`); - - } catch (error) { - console.error("āŒ Migration failed:", error); - process.exit(1); - } -} - -// Run migration -migrateUsers(); \ No newline at end of file diff --git a/scripts/migrate-tokens-encryption.ts b/scripts/migrate-tokens-encryption.ts deleted file mode 100644 index f9c1c6c..0000000 --- a/scripts/migrate-tokens-encryption.ts +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env bun -/** - * Migration script to encrypt existing GitHub and Gitea tokens in the database - * Run with: bun run scripts/migrate-tokens-encryption.ts - */ - -import { db, configs } from "../src/lib/db"; -import { eq } from "drizzle-orm"; -import { encrypt, isEncrypted, migrateToken } from "../src/lib/utils/encryption"; - -async function migrateTokens() { - console.log("Starting token encryption migration..."); - - try { - // Fetch all configs - const allConfigs = await db.select().from(configs); - - console.log(`Found ${allConfigs.length} configurations to check`); - - let migratedCount = 0; - let skippedCount = 0; - let errorCount = 0; - - for (const config of allConfigs) { - try { - let githubUpdated = false; - let giteaUpdated = false; - - // Parse configs - const githubConfig = typeof config.githubConfig === "string" - ? JSON.parse(config.githubConfig) - : config.githubConfig; - - const giteaConfig = typeof config.giteaConfig === "string" - ? JSON.parse(config.giteaConfig) - : config.giteaConfig; - - // Check and migrate GitHub token - if (githubConfig.token) { - if (!isEncrypted(githubConfig.token)) { - console.log(`Encrypting GitHub token for config ${config.id} (user: ${config.userId})`); - githubConfig.token = encrypt(githubConfig.token); - githubUpdated = true; - } else { - console.log(`GitHub token already encrypted for config ${config.id}`); - } - } - - // Check and migrate Gitea token - if (giteaConfig.token) { - if (!isEncrypted(giteaConfig.token)) { - console.log(`Encrypting Gitea token for config ${config.id} (user: ${config.userId})`); - giteaConfig.token = encrypt(giteaConfig.token); - giteaUpdated = true; - } else { - console.log(`Gitea token already encrypted for config ${config.id}`); - } - } - - // Update config if any tokens were migrated - if (githubUpdated || giteaUpdated) { - await db - .update(configs) - .set({ - githubConfig, - giteaConfig, - updatedAt: new Date(), - }) - .where(eq(configs.id, config.id)); - - migratedCount++; - console.log(`āœ“ Config ${config.id} updated successfully`); - } else { - skippedCount++; - } - - } catch (error) { - errorCount++; - console.error(`āœ— Error processing config ${config.id}:`, error); - } - } - - console.log("\n=== Migration Summary ==="); - console.log(`Total configs: ${allConfigs.length}`); - console.log(`Migrated: ${migratedCount}`); - console.log(`Skipped (already encrypted): ${skippedCount}`); - console.log(`Errors: ${errorCount}`); - - if (errorCount > 0) { - console.error("\nāš ļø Some configs failed to migrate. Please check the errors above."); - process.exit(1); - } else { - console.log("\nāœ… Token encryption migration completed successfully!"); - } - - } catch (error) { - console.error("Fatal error during migration:", error); - process.exit(1); - } -} - -// Verify environment setup -function verifyEnvironment() { - const requiredEnvVars = ["ENCRYPTION_SECRET", "JWT_SECRET", "BETTER_AUTH_SECRET"]; - const availableSecrets = requiredEnvVars.filter(varName => process.env[varName]); - - if (availableSecrets.length === 0) { - console.error("āŒ No encryption secret found!"); - console.error("Please set one of the following environment variables:"); - console.error(" - ENCRYPTION_SECRET (recommended)"); - console.error(" - JWT_SECRET"); - console.error(" - BETTER_AUTH_SECRET"); - process.exit(1); - } - - console.log(`Using encryption secret from: ${availableSecrets[0]}`); -} - -// Main execution -async function main() { - console.log("=== Gitea Mirror Token Encryption Migration ===\n"); - - // Verify environment - verifyEnvironment(); - - // Run migration - await migrateTokens(); - - process.exit(0); -} - -main().catch((error) => { - console.error("Unexpected error:", error); - process.exit(1); -}); \ No newline at end of file