diff --git a/src/app/api/auth/register/route.ts b/src/app/api/auth/register/route.ts index dc6b2b2..c70661b 100644 --- a/src/app/api/auth/register/route.ts +++ b/src/app/api/auth/register/route.ts @@ -1,5 +1,7 @@ import { NextResponse } from 'next/server'; import { registerUser, createSession } from '@/lib/auth'; +import { db, nodes, users } from '@/db'; +import { eq } from 'drizzle-orm'; import { z } from 'zod'; const registerSchema = z.object({ @@ -21,6 +23,22 @@ export async function POST(request: Request) { data.displayName ); + // Check if this is an NSFW node and auto-enable NSFW settings + const nodeDomain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000'; + const node = await db.query.nodes.findFirst({ + where: eq(nodes.domain, nodeDomain), + }); + + if (node?.isNsfw) { + // Auto-enable NSFW viewing and mark account as NSFW for users on NSFW nodes + await db.update(users) + .set({ + nsfwEnabled: true, + isNsfw: true + }) + .where(eq(users.id, user.id)); + } + // Create session for new user await createSession(user.id); diff --git a/src/app/explore/page.tsx b/src/app/explore/page.tsx index 2e83b96..01c479a 100644 --- a/src/app/explore/page.tsx +++ b/src/app/explore/page.tsx @@ -6,7 +6,8 @@ import { SearchIcon, TrendingIcon, UsersIcon } from '@/components/Icons'; import { PostCard } from '@/components/PostCard'; import { Post } from '@/lib/types'; import { formatFullHandle } from '@/lib/utils/handle'; -import { Bot, Network, Server } from 'lucide-react'; +import { Bot, Network, Server, EyeOff } from 'lucide-react'; +import { useAuth } from '@/lib/contexts/AuthContext'; interface User { id: string; @@ -75,6 +76,7 @@ interface SwarmPost { } export default function ExplorePage() { + const { user } = useAuth(); const [query, setQuery] = useState(''); const [activeTab, setActiveTab] = useState<'node' | 'swarm' | 'users' | 'search'>('node'); const [nodePosts, setNodePosts] = useState([]); @@ -84,6 +86,17 @@ export default function ExplorePage() { const [searchResults, setSearchResults] = useState<{ posts: Post[]; users: User[] }>({ posts: [], users: [] }); const [loading, setLoading] = useState(true); const [searching, setSearching] = useState(false); + const [isNsfwNode, setIsNsfwNode] = useState(false); + + // Fetch node info to check if NSFW + useEffect(() => { + fetch('/api/node') + .then(res => res.json()) + .then(data => { + setIsNsfwNode(data.isNsfw || false); + }) + .catch(() => {}); + }, []); useEffect(() => { // Load node posts (local only) @@ -232,7 +245,17 @@ export default function ExplorePage() {
{activeTab === 'node' && ( - loading ? ( + !user && isNsfwNode ? ( +
+ +

+ Adult Content +

+

+ This node contains adult or sensitive content. You must be 18 or older and signed in to view posts. +

+
+ ) : loading ? (
Loading posts...
) : nodePosts.length === 0 ? (
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index a7ad8ec..088b86a 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -15,8 +15,9 @@ export default function LoginPage() { const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const [nodeInfoLoaded, setNodeInfoLoaded] = useState(false); - const [nodeInfo, setNodeInfo] = useState<{ name: string; description: string; logoUrl?: string }>({ name: '', description: '' }); + const [nodeInfo, setNodeInfo] = useState<{ name: string; description: string; logoUrl?: string; isNsfw?: boolean }>({ name: '', description: '' }); const [handleStatus, setHandleStatus] = useState<'idle' | 'checking' | 'available' | 'taken'>('idle'); + const [ageVerified, setAgeVerified] = useState(false); // Import specific state const [importFile, setImportFile] = useState(null); @@ -33,7 +34,8 @@ export default function LoginPage() { setNodeInfo({ name: data.name || '', description: data.description || 'Synapsis is designed to function like a global signal layer rather than a culture-bound platform. Anyone can run their own node and still participate in a shared, interconnected network, with global identity, clean terminology, and a modern interface that feels current rather than experimental. Synapsis aims to be neutral, resilient infrastructure for human and machine discourse, more like a protocol or nervous system than a social club.', - logoUrl: data.logoUrl || undefined + logoUrl: data.logoUrl || undefined, + isNsfw: data.isNsfw || false }); setNodeInfoLoaded(true); }) @@ -122,6 +124,11 @@ export default function LoginPage() { return; } + if (mode === 'register' && nodeInfo.isNsfw && !ageVerified) { + setError('You must verify your age to register on this node'); + return; + } + setLoading(true); try { @@ -380,6 +387,30 @@ export default function LoginPage() {
)} + {mode === 'register' && nodeInfo.isNsfw && ( +
+ +
+ )} +