diff --git a/docker-compose.yml b/docker-compose.yml index 96db6f6..8d7c8a2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,16 +4,22 @@ services: build: . image: falah-mobile:latest ports: - - "4011:3000" + - "4013:3000" environment: - NODE_ENV=production - JWT_SECRET=${JWT_SECRET:-flh-dev-jwt-secret-change-in-prod} - DATABASE_URL=file:./dev.db + - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID:-} + - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET:-} + - APPLE_CLIENT_ID=${APPLE_CLIENT_ID:-} + - APPLE_CLIENT_SECRET=${APPLE_CLIENT_SECRET:-} + - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID:-} + - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-} volumes: - falah-mobile-data:/app/data restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"] + test: ["CMD", "curl", "-f", "http://localhost:3000/mobile/api/health"] interval: 30s timeout: 10s retries: 3 diff --git a/scripts/setup-sso.sh b/scripts/setup-sso.sh new file mode 100644 index 0000000..0c4a20b --- /dev/null +++ b/scripts/setup-sso.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# ============================================================ +# FalahOS SSO Credentials Setup Script +# ============================================================ +# Run this on your Contabo VPS after getting OAuth credentials. +# It safely updates .env, rebuilds, and redeploys. +# +# Usage: bash /root/falah-mobile/scripts/setup-sso.sh +# ============================================================ + +set -e + +SSO_DIR="$(cd "$(dirname "$0")/.." && pwd)" +ENV_FILE="$SSO_DIR/.env" +COMPOSE_FILE="$SSO_DIR/docker-compose.yml" + +echo "╔═══════════════════════════════════════════════╗" +echo "║ FalahOS SSO Credentials Setup ║" +echo "╚═══════════════════════════════════════════════╝" +echo "" + +# --- Prompt for GitHub --- +echo "── 🐙 GitHub OAuth App ──" +read -p " Client ID : " GITHUB_CLIENT_ID +read -sp " Client Secret: " GITHUB_CLIENT_SECRET +echo "" +echo "" + +# --- Prompt for Google --- +echo "── 🔵 Google OAuth ──" +read -p " Client ID : " GOOGLE_CLIENT_ID +read -sp " Client Secret: " GOOGLE_CLIENT_SECRET +echo "" +echo "" + +# --- Prompt for Apple --- +echo "── 🍎 Apple Sign In ──" +read -p " Service ID : " APPLE_CLIENT_ID +read -sp " Client Secret: " APPLE_CLIENT_SECRET +echo "" +echo "" + +# --- Confirm --- +echo "═══════════════════════════════════════════════" +echo " Summary:" +echo " GitHub: ${GITHUB_CLIENT_ID:0:10}..." +echo " Google: ${GOOGLE_CLIENT_ID:0:10}..." +echo " Apple: $APPLE_CLIENT_ID" +echo "═══════════════════════════════════════════════" +read -p "Apply these credentials and redeploy? (y/N) " CONFIRM + +if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then + echo "Aborted. No changes made." + exit 0 +fi + +# --- Backup current .env --- +cp "$ENV_FILE" "$ENV_FILE.backup" +echo "✓ Backed up .env → .env.backup" + +# --- Remove old OAuth lines if they exist --- +sed -i '/^GOOGLE_CLIENT_ID=/d' "$ENV_FILE" +sed -i '/^GOOGLE_CLIENT_SECRET=/d' "$ENV_FILE" +sed -i '/^APPLE_CLIENT_ID=/d' "$ENV_FILE" +sed -i '/^APPLE_CLIENT_SECRET=/d' "$ENV_FILE" +sed -i '/^GITHUB_CLIENT_ID=/d' "$ENV_FILE" +sed -i '/^GITHUB_CLIENT_SECRET=/d' "$ENV_FILE" + +# --- Append new credentials --- +cat >> "$ENV_FILE" << EOF + +# --- OAuth / SSO --- +GOOGLE_CLIENT_ID="$GOOGLE_CLIENT_ID" +GOOGLE_CLIENT_SECRET="$GOOGLE_CLIENT_SECRET" +APPLE_CLIENT_ID="$APPLE_CLIENT_ID" +APPLE_CLIENT_SECRET="$APPLE_CLIENT_SECRET" +GITHUB_CLIENT_ID="$GITHUB_CLIENT_ID" +GITHUB_CLIENT_SECRET="$GITHUB_CLIENT_SECRET" +EOF + +echo "✓ Credentials written to .env" + +# --- Rebuild and deploy --- +echo "" +echo "═══ Building & Deploying ═══" +cd "$SSO_DIR" +npm run build + +echo "" +echo "═══ Rebuilding Docker image ═══" +docker compose -f "$COMPOSE_FILE" build --pull + +echo "" +echo "═══ Restarting container ═══" +docker compose -f "$COMPOSE_FILE" up -d --force-recreate + +echo "" +echo "✓ SSO setup complete!" +echo " Test at: https://falahos.my/mobile/auth" diff --git a/src/app/setup/page.tsx b/src/app/setup/page.tsx new file mode 100644 index 0000000..e523c80 --- /dev/null +++ b/src/app/setup/page.tsx @@ -0,0 +1,582 @@ +'use client'; + +import { useState } from 'react'; + +export default function SetupPage() { + const [tab, setTab] = useState<'github' | 'google' | 'apple' | 'env'>('github'); + const [copied, setCopied] = useState(''); + + const copyToClipboard = (text: string, label: string) => { + navigator.clipboard.writeText(text).then(() => { + setCopied(label); + setTimeout(() => setCopied(''), 2000); + }).catch(() => { + // Fallback + const ta = document.createElement('textarea'); + ta.value = text; + document.body.appendChild(ta); + ta.select(); + document.execCommand('copy'); + document.body.removeChild(ta); + setCopied(label); + setTimeout(() => setCopied(''), 2000); + }); + }; + + const tabs = [ + { id: 'github' as const, label: 'GitHub', icon: '🐙' }, + { id: 'google' as const, label: 'Google', icon: '🔵' }, + { id: 'apple' as const, label: 'Apple', icon: '🍎' }, + { id: 'env' as const, label: 'Apply', icon: '⚡' }, + ]; + + return ( +
+

+ ⚡ SSO Setup Guide +

+

+ Create OAuth credentials for Google, Apple, and GitHub SSO. + Each takes ~5 minutes. +

+ + {/* Tab bar */} +
+ {tabs.map(t => ( + + ))} +
+ + {/* GitHub Tab */} + {tab === 'github' && ( +
+

+ Create a GitHub OAuth App +

+ + +

Open this link in your browser:

+ +
+ + +

Click "New OAuth App" button (top right).

+
+ + + + + + + + + +

Click "Register application".

+
+ + +

You will see:

+
    +
  • Client ID — copy this
  • +
  • Client Secret — click "Generate a new client secret" and copy it
  • +
+ +

+ Paste them below when you have them: +

+
+
+ GITHUB_CLIENT_ID=your_client_id_here +
+
+ GITHUB_CLIENT_SECRET=your_client_secret_here +
+ "\nGITHUB_CLIENT_SECRET=""`} + label="github-template" + copied={copied} + onCopy={copyToClipboard} + /> +
+
+
+ )} + + {/* Google Tab */} + {tab === 'google' && ( +
+

+ Create Google OAuth 2.0 Client +

+ + + + + + +

If you don't have a project, click "Create Project" and name it "FalahOS".

+
+ + +

Click "OAuth consent screen" (left sidebar).

+
    +
  • Choose External user type
  • +
  • App name: FalahOS
  • +
  • User support email: your email
  • +
  • Developer Contact: your email
  • +
  • Add scopes: email, profile, openid
  • +
  • Add test users: your email
  • +
+
+ + +

Click "Create Credentials" → "OAuth client ID".

+ + + + +
+ + +

Click "Create" and copy the popup values:

+
+
+ GOOGLE_CLIENT_ID=xxxxxxxxx.apps.googleusercontent.com +
+
+ GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxx +
+ "\nGOOGLE_CLIENT_SECRET=""`} + label="google-template" + copied={copied} + onCopy={copyToClipboard} + /> +
+
+
+ )} + + {/* Apple Tab */} + {tab === 'apple' && ( +
+

+ Set Up Sign In with Apple +

+ + + +

+ ⚠️ Requires an Apple Developer account ($99/year). +

+
+ + +
    +
  • Click "+""Service IDs"
  • +
  • Description: FalahOS Auth
  • +
  • Identifier: com.falahos.auth
  • +
  • Click "Continue""Register"
  • +
+
+ + +
    +
  • Click on your new Service ID
  • +
  • Check "Sign in with Apple""Configure"
  • +
  • Select "Use as default" or create a new Service
  • +
  • Web Domain: falahos.my
  • +
  • Return URLs: https://falahos.my/mobile/api/auth/apple/callback
  • +
  • Click "Save"
  • +
+
+ + +
    +
  • Go to Keys"+"
  • +
  • Select "Sign in with Apple"
  • +
  • Configure with your Service ID
  • +
  • Download the .p8 key file
  • +
  • Note the Key ID
  • +
+
+ + +
+
+ APPLE_CLIENT_ID=com.falahos.auth (your Service ID) +
+
+ APPLE_CLIENT_SECRET= (generated JWT, not needed immediately) +
+ +
+
+
+ )} + + {/* Apply Tab */} + {tab === 'env' && ( +
+

+ Apply Credentials & Deploy +

+ +

+ Once you have your credentials from all providers, paste them below + and we'll configure the server. +

+ + +
+ )} + +
+

+ ✅ Quick Summary +

+

+ After creating all 3 OAuth apps, you'll have: +

+ +

+ Contact me on Telegram with the values and I'll apply them instantly. + Or use the SSH command below to configure yourself. +

+
+
+ ); +} + +function Step({ number, title, children }: { number: number; title: string; children: React.ReactNode }) { + return ( +
+
+ + {number} + +

{title}

+
+
+ {children} +
+
+ ); +} + +function FormField({ label, value }: { label: string; value: string }) { + return ( +
+
{label}
+
+ {value} +
+
+ ); +} + +function CodeBlock({ text, label, copied, onCopy }: { + text: string; + label: string; + copied: string; + onCopy: (text: string, label: string) => void; +}) { + return ( +
+
+ {text} +
+ +
+ ); +} + +function CopyButton({ text, label, copied, onCopy }: { + text: string; + label: string; + copied: string; + onCopy: (text: string, label: string) => void; +}) { + return ( + + ); +} + +function EnvForm() { + const [ghId, setGhId] = useState(''); + const [ghSecret, setGhSecret] = useState(''); + const [glId, setGlId] = useState(''); + const [glSecret, setGlSecret] = useState(''); + const [apId, setApId] = useState(''); + const [apSecret, setApSecret] = useState(''); + const [submitted, setSubmitted] = useState(false); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + // Build the env var text for copying + const text = `# Paste these into your VPS:\ncd /root/falah-mobile\ncat >> .env << 'EOF'\nGOOGLE_CLIENT_ID="${glId}"\nGOOGLE_CLIENT_SECRET="${glSecret}"\nAPPLE_CLIENT_ID="${apId}"\nAPPLE_CLIENT_SECRET="${apSecret}"\nGITHUB_CLIENT_ID="${ghId}"\nGITHUB_CLIENT_SECRET="${ghSecret}"\nEOF\ndocker compose up -d --build`; + navigator.clipboard.writeText(text).then(() => { + setSubmitted(true); + setTimeout(() => setSubmitted(false), 3000); + }).catch(() => setSubmitted(true)); + }; + + return ( +
+
+

🐙 GitHub

+ + +
+ +
+

🔵 Google

+ + +
+ +
+

🍎 Apple

+ + +
+ + + +

+ This copies the deployment command to your clipboard. Send it to me on Telegram + and I'll run it on the VPS. +

+
+ ); +} + +function InputField({ label, value, onChange, placeholder, secret }: { + label: string; + value: string; + onChange: (v: string) => void; + placeholder: string; + secret?: boolean; +}) { + return ( +
+
{label}
+ onChange(e.target.value)} + placeholder={placeholder} + style={{ + width: '100%', + padding: '8px 10px', + background: '#0a0a0a', + border: '1px solid #333', + borderRadius: '6px', + fontSize: '14px', + color: '#fff', + fontFamily: 'monospace', + outline: 'none', + boxSizing: 'border-box', + }} + /> +
+ ); +}