This is a full-stack polling application built with Next.js and Supabase. It allows users to create polls, vote on them, and view the results in real-time.
- Framework: Next.js (with App Router)
- Authentication: Supabase Auth
- Database: Supabase (Postgres)
- Styling: Tailwind CSS
- UI Components: shadcn/ui
- Language: TypeScript
- Testing: Jest
- User authentication (Sign up, Sign in)
- Create, view, edit, and delete polls
- Vote on polls
- Real-time poll results
- Protected routes for authenticated users
To run this project locally, follow these steps:
git clone <repository-url>
cd polly-appnpm install- Create a new project on Supabase.
- Go to the SQL Editor in your Supabase project dashboard.
- Run the SQL statements from
supabase/migrationsto create the necessary tables (polls,poll_options,votes). - Go to Project Settings > API to find your project URL and API keys.
Create a .env.local file in the root of the project and add the following variables:
NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
SUPABASE_SECRET_KEY=your-supabase-secret-key
Replace your-supabase-project-url and your-supabase-secret-key with the values from your Supabase project.
Once the setup is complete, you can run the development server:
npm run devOpen http://localhost:3000 with your browser to see the application.
To run the tests, use the following command:
npm testThis will run the Jest tests for the application.
- Sign up for an account or sign in.
- Navigate to the "Create Poll" page.
- Fill in the title, an optional description, and at least two options.
- Click "Create Poll" to submit.
- From the main polls page, click on a poll to view it.
- Select an option to vote for.
- Click "Submit Vote".
- After voting, you will see the poll results.
During a recent security review, critical vulnerabilities were identified and have been remediated. This section outlines the issues and the steps taken to fix them.
Vulnerability:
The initial implementation of the Next.js Server Actions in lib/poll-actions.ts was vulnerable to user impersonation. The createPoll, votePoll, and deletePoll functions received user identity (creatorId, voterId, userId) directly from the client-side FormData. A malicious user could easily manipulate this data to perform actions on behalf of other users.
For example, an attacker could have created a poll or cast a vote as any other user by simply providing that user's ID in the form submission.
Remediation:
The vulnerability was fixed by enforcing server-side authentication and authorization within the Server Actions:
-
Server-Side User Authentication: The updated Server Actions now use the
@supabase/ssrlibrary to create a server-side Supabase client. This client securely retrieves the authenticated user's session from the browser's cookies. -
Enforced User Identity: The
creatorId,voterId, anduserIdare no longer read from the client-sideFormData. Instead, the functions now rely exclusively on theuser.idobtained from the secure, server-side session. If no user is authenticated, the actions throw anAuthenticationError. -
Client-Side Code Update: The client-side code in
app/create-poll/page.tsxandapp/polls/[id]/page.tsxwas refactored to stop sending user IDs in theFormData. These pages now call the secure Server Actions.
This ensures that all actions are performed by the currently logged-in user, preventing any possibility of user impersonation.
Vulnerability:
Several components, such as app/create-poll/page.tsx and app/polls/[id]/page.tsx, were making direct calls to the Supabase database from the client-side. This approach is not recommended as it can lead to security risks if Row Level Security (RLS) is not perfectly configured. It also tightly couples the frontend with the database schema.
Remediation:
The client-side components were refactored to use the newly secured Server Actions (createPoll, votePoll, etc.) instead of direct database calls. This change centralizes the application's business logic and data access on the server, providing a more secure and maintainable architecture.