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-cli
for 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
backend
directory:cd backend
- Install dependencies:
npm install
(oryarn install
) - Create a
.env
file by copying../.env.example
(from the project root) to this directory (backend/.env
).- Update
DATABASE_URL
to point to your PostgreSQL database. This is crucial. Example:postgresql://your_db_user:your_db_password@localhost:5432/signalbot_db
- Set
JWT_SECRET
to a long, random string. - Set
BOT_NUMBER
to the phone number yoursignal-cli
instance is using (e.g.,+1234567890
). - Set
SIGNAL_CLI_REST_API_URL
(e.g.,http://localhost:8080
ifsignal-cli
runs on the same machine with default port, or the appropriate URL ifsignal-cli
uses a different port or host, likehttp://localhost:7446
if using the port from thesignal-cli.service.example
). - Set
BASE_URL
for constructing webhook URLs (e.g.,http://yourdomain.com
orhttp://localhost:PORT_YOUR_BACKEND_RUNS_ON
). - Set
FRONTEND_BASE_URL
(e.g.,http://localhost:3000
or 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.,587
for TLS,465
for 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
psql
or 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_URL
in yourbackend/.env
file matches the database name, user, password, host, and port you configured.
- Example using
- Run Database Migrations:
- Once the database is created and the
.env
file 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-migrate
and 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-migrate
works 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 timestamp
orNo migrations to run!
errors: This often indicates an issue with the migration filename not matching the expected format, ornode-pg-migrate
thinking a migration has already run (check thepgmigrations
table in your database). Renaming the file to include a timestamp or creating a new one as described above usually resolves this. You can inspect thepgmigrations
table in your database (e.g.,SELECT * FROM pgmigrations;
inpsql
) to see which migrationsnode-pg-migrate
considers applied.MODULE_TYPELESS_PACKAGE_JSON
Warning: You might see a Node.js warning about module types if your migration file uses ES Module syntax but yourbackend/package.json
does 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.js
files in the backend project).- Verify Schema: After running
npm run migrate up
successfully, 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:3000
or the port specified in your.env
(e.g., via aPORT
variable if yourserver.js
uses it). Check your terminal output and.env
configuration.
- The backend typically runs on
- Update
- Navigate to the
-
Frontend Setup (
frontend/
):- Navigate to the
frontend
directory:cd ../frontend
(frombackend/
) orcd frontend
(from project root). - Install dependencies:
npm install
(oryarn install
) - (Optional) Create a
.env.local
file in thefrontend
directory 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-cli
Setup:- Ensure
signal-cli
is running and configured with the phone number specified in the backend'sBOT_NUMBER
environment 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-cli
directly (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_id
needs to be fully implemented and verified. Thesignal_group_id
in thegroups
table 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
POST
request to a webhook URL with a JSON payload like:The backend will then use{ "message": "Hello from your external service!" }
signalService
to 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/register
POST /auth/login
POST /auth/forgot-password
POST /auth/reset-password
POST /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-password
andPOST /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.example
backend.service.example
signal-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:User
andGroup
: 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-cli
on Linux is often~/.config/signal-cli
for a user or a system-wide path like/opt/signal-cli/data
or/etc/signal-cli/data
depending 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-cli
port 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.service
file:[Unit] Description=My Backend Service After=network.target postgresql.service Wants=postgresql.service ...
Repeat these steps for backend.service
, adjusting names and paths accordingly.