This project provides a web-based platform to create, manage and interact with Webhooks for Signal. It allows users to register, create groups, and configure webhooks to send messages to groups via signal-cli. The first registered user automatically gains administrative privileges to manage users, groups, and webhooks directly within the frontend interface.
Automatic Signal group linking, there's no need for a difficult solution.
This service is an early alpha, everything can happen and break. There's no guarantee that it's safe, stable or something else.
- User Authentication: Secure registration and login for users using JWT.
- Automated Admin Assignment: The first user to register on the platform automatically becomes an administrator.
- Group Management: Users can create, view, edit, and delete "groups" within the platform.
- Bot Linking Mechanism: Functionality to generate a link token for associating a bot (running via
signal-cli) with a platform group and a Signal group. - Webhook Management:
- Create unique webhooks for each group.
- View and delete webhooks.
- Webhook URLs can be used by external services to send messages to the linked Signal group.
- Message Sending: A public endpoint (
/webhook/:webhookToken) receives messages and forwards them to the appropriate Signal group usingsignal-cli. - Integrated Admin Interface: Administrators can manage users, all groups, and all webhooks via a dedicated section within the main frontend application (e.g.,
/dashboard/admin).
- Frontend: Next.js (React framework) - located in
frontend/ - Backend: Node.js with Express.js - located in
backend/ - Database: PostgreSQL
- Signal Integration: Relies on
signal-clifor communication with the Signal network.
- Node.js and npm/yarn: For both backend and frontend.
- PostgreSQL Server: Running and accessible.
signal-cli: Installed, configured with a dedicated bot phone number, and running. The API should be accessible by the backend.
signalcow/
├── backend/ # Node.js/Express backend
│ ├── config/ # Database configuration (db.js)
│ ├── middleware/ # Authentication middleware (authMiddleware.js, adminAuthMiddleware.js)
│ ├── routes/ # API routes (authRoutes.js, groupRoutes.js, webhookRoutes.js, admin.js)
│ ├── services/ # Business logic (signalService.js)
│ └── server.js # Main backend server file
├── frontend/ # Next.js frontend
│ ├── src/
│ │ ├── app/ # Next.js app router (pages, layouts, components)
│ │ └── ...
│ ├── public/ # Static assets
│ ├── package.json
│ └── ...
├── migrations/ # Database migration files (using node-pg-migrate)
├── .env.example # Example environment file (copy to .env and configure)
├── .gitignore
├── LICENSE
└── README.md
-
Clone the Repository:
git clone <your-repository-url> cd signalcow
-
Backend Setup (
backend/):- Navigate to the
backenddirectory:cd backend - Install dependencies:
npm install(oryarn install) - Create a
.envfile by copying../.env.example(from the project root) to this directory (backend/.env).- Update
DATABASE_URLto point to your PostgreSQL database. This is crucial. Example:postgresql://your_db_user:your_db_password@localhost:5432/signalbot_db - Set
JWT_SECRETto a long, random string. - Set
BOT_NUMBERto the phone number yoursignal-cliinstance is using (e.g.,+1234567890). - Set
SIGNAL_CLI_REST_API_URL(e.g.,http://localhost:8080ifsignal-cliruns on the same machine with default port, or the appropriate URL ifsignal-cliuses a different port or host, likehttp://localhost:7446if using the port from thesignal-cli.service.example). - Set
BASE_URLfor constructing webhook URLs (e.g.,http://yourdomain.comorhttp://localhost:PORT_YOUR_BACKEND_RUNS_ON). - Set
FRONTEND_BASE_URL(e.g.,http://localhost:3000or your frontend's public URL) - this is used for generating links in password reset emails. - Email (SMTP) Configuration (for Password Reset):
SMTP_HOST: Hostname of your SMTP server (e.g.,smtp.example.com).SMTP_PORT: Port for your SMTP server (e.g.,587for TLS,465for SSL).SMTP_USER: Username for SMTP authentication (e.g.,user@example.com).SMTP_PASS: Password for SMTP authentication.SMTP_FROM_EMAIL: The "From" address for password reset emails (e.g.,"SignalCow Password Reset" <noreply@example.com>).
- Database Setup (PostgreSQL):
- Ensure you have a PostgreSQL server installed and running.
- You need to create a dedicated database and a user for the application. You can do this using
psqlor a database management tool.- Example using
psql(connect as a superuser, e.g.,postgres):-- Connect to PostgreSQL -- sudo -u postgres psql CREATE DATABASE signalbot_db; CREATE USER signalbot_user WITH PASSWORD 'your_secure_password'; GRANT ALL PRIVILEGES ON DATABASE signalbot_db TO signalbot_user; -- Optionally, if you want the user to be able to create tables etc. within a specific schema or the public schema: -- \c signalbot_db -- GRANT ALL ON SCHEMA public TO signalbot_user;
- Make sure the
DATABASE_URLin yourbackend/.envfile matches the database name, user, password, host, and port you configured.
- Example using
- Run Database Migrations:
- Once the database is created and the
.envfile is configured, navigate to thebackend/directory (if not already there). - Run the following command to create the necessary tables and schema in your database:
npm run migrate up
- This command uses
node-pg-migrateand executes the migration files located in the project's rootmigrations/directory (e.g.,migrations/001_initial_schema.js). This step is essential for the application to function correctly. - Troubleshooting Migrations:
- Naming Convention:
node-pg-migrateworks best when migration files start with a timestamp (e.g.,1622548800000_initial_schema.js). To generate a new migration file with the correct naming convention, use:Then, add your schema changes to thenpm run migrate:create descriptive_migration_name
up(anddown) functions in the newly generated file. Can't determine timestamporNo migrations to run!errors: This often indicates an issue with the migration filename not matching the expected format, ornode-pg-migratethinking a migration has already run (check thepgmigrationstable in your database). Renaming the file to include a timestamp or creating a new one as described above usually resolves this. You can inspect thepgmigrationstable in your database (e.g.,SELECT * FROM pgmigrations;inpsql) to see which migrationsnode-pg-migrateconsiders applied.MODULE_TYPELESS_PACKAGE_JSONWarning: You might see a Node.js warning about module types if your migration file uses ES Module syntax but yourbackend/package.jsondoes not specify"type": "module". As long as the migration completes successfully, this warning can often be ignored. To resolve it, ensure your migration files use CommonJS syntax (e.g.,exports.up = ...) or add"type": "module"tobackend/package.json(this will affect all.jsfiles in the backend project).- Verify Schema: After running
npm run migrate upsuccessfully, it is crucial to connect to your PostgreSQL database (e.g., usingpsql) and verify that the tables and columns were created as expected. For example:# Connect to your database, then: \dt # List all tables \d users # Describe the 'users' table to check its columns \d groups # Describe the 'groups' table # etc. for other tables
- Naming Convention:
- Once the database is created and the
- Start the backend server:
npm start- The backend typically runs on
http://localhost:3000or the port specified in your.env(e.g., via aPORTvariable if yourserver.jsuses it). Check your terminal output and.envconfiguration.
- The backend typically runs on
- Update
- Navigate to the
-
Frontend Setup (
frontend/):- Navigate to the
frontenddirectory:cd ../frontend(frombackend/) orcd frontend(from project root). - Install dependencies:
npm install(oryarn install) - (Optional) Create a
.env.localfile in thefrontenddirectory if you need to override default Next.js environment variables or set frontend-specific ones. For example, to set the API URL:NEXT_PUBLIC_API_URL=http://localhost:3000/api - Start the Next.js development server:
npm run dev- The frontend typically runs on
http://localhost:3001(or another port if 3000 is taken by the backend and Next.js auto-selects). Check your terminal output.
- The frontend typically runs on
- Navigate to the
-
signal-cliSetup:- Ensure
signal-cliis running and configured with the phone number specified in the backend'sBOT_NUMBERenvironment variable. - The backend needs to be able to reach this API (e.g., at
http://localhost:8080). - Start like this command:
signal-cli --config /opt/signal-cli -u +1234567890 daemon --tcp 0.0.0.0:7446
- Ensure
- Register & Login: Access the frontend (e.g.,
http://localhost:3000) to register a new user account and log in. The first user to register will automatically be granted administrator privileges. - Create a Group: Navigate to the groups section and create a new group. This represents a Signal group you want the bot to interact with.
- Link Bot to Signal Group (Partially Manual):
- In the group details page on the frontend, there should be an option to generate/retrieve a "Link Token" and your
BOT_NUMBER. - You currently need to use
signal-clidirectly (e.g., via curl or a tool like Postman):- Make the bot (identified by
BOT_NUMBER) join the target Signal group using its Signal Group ID. - Send the retrieved "Link Token" as a message from the bot's number to that Signal group.
- Make the bot (identified by
- The backend has a mechanism (
POST /api/groups/:groupId/link-token) to generate this token. The process of the bot sending this token to the group and the platform then automatically recognizing and associating thesignal_group_idneeds to be fully implemented and verified. Thesignal_group_idin thegroupstable is currently expected to be populated after this linking process.
- In the group details page on the frontend, there should be an option to generate/retrieve a "Link Token" and your
- Create Webhooks: For a linked group, create one or more webhooks. The platform will provide a unique URL for each webhook.
- Send Messages: Make a
POSTrequest to a webhook URL with a JSON payload like:The backend will then use{ "message": "Hello from your external service!" }signalServiceto send this message to the linked Signal group viasignal-cli. - Admin Panel: If you are the administrator (the first registered user), you can access the admin interface by navigating to the "Admin" section in the dashboard (typically
/dashboard/admin). Here you can manage all users, groups, and webhooks across the platform.
All API endpoints are prefixed with /api. Authentication is required for most group and webhook management endpoints. Admin-specific endpoints require the user to have admin privileges.
- Auth:
POST /auth/registerPOST /auth/loginPOST /auth/forgot-passwordPOST /auth/reset-passwordPOST /auth/change-password(Authenticated users)
- Groups (User-specific):
GET /groups(Lists groups for the authenticated user)POST /groups(Creates a new group)GET /groups/:groupId(Gets a specific group for the authenticated user)PUT /groups/:groupId(Updates a specific group for the authenticated user)DELETE /groups/:groupId(Deletes a specific group for the authenticated user)POST /groups/:groupId/link-token(Generates/retrieves a token for linking the bot)GET /groups/:groupId/webhooks(Lists webhooks for a specific group of the authenticated user)POST /groups/:groupId/webhooks(Creates a new webhook for a group of the authenticated user)
- Webhooks (Management - User-specific for deletion, although creation is via group route):
- Note: Webhook creation is done via
POST /api/groups/:groupId/webhooks. - Deletion of a specific webhook by its owner would typically be
DELETE /api/groups/:groupId/webhooks/:webhookId(This needs to be verified/implemented if not already present in groupRoutes.js).
- Note: Webhook creation is done via
- Admin API (
/api/admin- requires admin privileges):GET /admin/users(Lists all users)DELETE /admin/users/:userId(Deletes a specific user)GET /admin/groups(Lists all groups in the system)DELETE /admin/groups/:groupId(Deletes a specific group)GET /admin/webhooks(Lists all webhooks in the system)DELETE /admin/webhooks/:webhookId(Deletes a specific webhook)
- Webhook (Public Message Receiver):
POST /webhook/:webhookToken(Receives a message to be sent to a Signal group)
The backend provides an interactive API documentation using Swagger UI. This allows you to explore and test the API endpoints directly from your browser.
- Accessing Swagger UI: Once the backend server is running, you can access the Swagger UI at the
/api-docs/endpoint. For example, if your backend is running onhttp://localhost:3001, the Swagger UI will be available athttp://localhost:3001/api-docs/. - Features:
- View all available API endpoints, including those for authentication, group management, webhook management, and admin functionalities.
- See details for each endpoint, including required parameters, request body structure, and possible responses.
- Execute API requests directly from the UI to test the endpoints (Note: For protected routes, you will need to authorize your session by providing a JWT token using the "Authorize" button, usually found at the top right of the Swagger UI page).
- Password Reset Routes: The API documentation includes endpoints for
POST /api/auth/forgot-passwordandPOST /api/auth/reset-password, which are part of the authentication flow.
This project is licensed under the GNU General Public License v3.0.
To run the frontend, backend, and signal-cli services persistently on a Linux server (e.g., Ubuntu), using systemd is a recommended approach. This allows the services to start on boot, restart on failure, and manage logging.
Example systemd unit files are provided in the root of this repository:
frontend.service.examplebackend.service.examplesignal-cli.service.example
Please see nginx.vhost.example.conf
General Steps for each service:
-
Copy the Example File: Copy the relevant example file (e.g.,
frontend.service.example) to/etc/systemd/system/frontend.service(adjusting the target filename as needed, e.g.,signalbot-frontend.service).sudo cp frontend.service.example /etc/systemd/system/frontend.service
-
Edit the Service File: Open the new service file with a text editor (e.g.,
sudo vim /etc/systemd/system/frontend.service) and carefully review and update all paths and settings according to your server environment:UserandGroup: Set to a non-privileged user that will run the service.WorkingDirectory: Set to the absolute path where the service's code (e.g., frontend, backend) is located on your server (e.g.,/srv/signalbot/frontend).ExecStart:- Ensure the command and any paths to executables (like
node,npm,next,signal-cli) are correct for your server. - For
frontend.service, ensure you have a production build (e.g.,npm run build) and update the port if needed. - For
signal-cli.service, crucially update/PATH_TO_YOUR/signal-cli,/PATH_TO_YOUR_SIGNAL_CONFIG_DIR, and+YOUR_SIGNAL_NUMBER. The config directory forsignal-clion Linux is often~/.config/signal-clifor a user or a system-wide path like/opt/signal-cli/dataor/etc/signal-cli/datadepending on your installation method.
- Ensure the command and any paths to executables (like
Environment: Set necessary environment variables (e.g.,NODE_ENV=production,DATABASE_URL,PORTs).
-
Reload systemd Daemon: After creating or modifying a service file, tell systemd to reload its configuration:
sudo systemctl daemon-reload
-
Enable the Service (to start on boot):
sudo systemctl enable frontend.service(Use the actual filename you chose, e.g.,
signalbot-frontend.service) -
Start the Service Manually:
sudo systemctl start frontend.service
-
Check the Service Status:
sudo systemctl status frontend.service
This will show if the service is active (running) and display recent log entries. Look for any errors.
-
View Logs: To view more detailed logs or follow them live:
journalctl -u frontend.service journalctl -u frontend.service -f # Follow live logs
Important Considerations:
- Permissions: Ensure the user specified in the service file has the necessary read/write/execute permissions for the
WorkingDirectory, any config files, and log directories. - Firewall: Make sure any ports your services listen on (e.g., frontend port, backend port,
signal-cliport 7446) are opened in your server's firewall (e.g.,ufw) if you don't use a webserver and reverse proxy. Example forufw:sudo ufw allow 3000/tcp # Example for frontend sudo ufw allow 8000/tcp # Example for backend sudo ufw allow 7446/tcp # For signal-cli sudo ufw enable sudo ufw status
- Production Builds: Always use production builds for your frontend and backend services for better performance and security. Run in /frontend
npx build. - Database Service: If your backend depends on a database, ensure the database service (e.g.,
postgresql.service) is started before your backend. You can add it to theAfter=andWants=directives in yourbackend.servicefile:[Unit] Description=My Backend Service After=network.target postgresql.service Wants=postgresql.service ...
Repeat these steps for backend.service, adjusting names and paths accordingly.