diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 00000000..b865e90d --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,65 @@ +name: Docker Build and Push + +on: + push: + branches: + - master + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Get short commit SHA + id: commit + run: echo "SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ secrets.DOCKER_HUB_USERNAME }}/faucet + tags: | + type=raw,value=latest + type=raw,value=latest-${{ steps.commit.outputs.SHORT_SHA }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + cache-from: type=registry,image=${{ secrets.DOCKER_HUB_USERNAME }}/faucet:latest + cache-to: type=inline + + - name: Display Docker image tags + run: | + echo "==========================================" + echo "✅ Docker image built and pushed successfully!" + echo "==========================================" + echo "" + echo "📦 Image: ${{ secrets.DOCKER_HUB_USERNAME }}/faucet" + echo "" + echo "🏷️ Available tags:" + echo " • latest" + echo " • latest-${{ steps.commit.outputs.SHORT_SHA }}" + echo "" + echo "📋 Pull commands:" + echo " docker pull ${{ secrets.DOCKER_HUB_USERNAME }}/faucet:latest" + echo " docker pull ${{ secrets.DOCKER_HUB_USERNAME }}/faucet:latest-${{ steps.commit.outputs.SHORT_SHA }}" + echo "" + echo "🔗 Commit: ${{ github.sha }}" + echo " Short SHA: ${{ steps.commit.outputs.SHORT_SHA }}" + echo "==========================================" diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml new file mode 100644 index 00000000..2bd26836 --- /dev/null +++ b/.github/workflows/pr-test.yml @@ -0,0 +1,42 @@ +name: PR Test + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run tests + run: pnpm test diff --git a/README.md b/README.md index b9f28a41..3f8ed8b9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,90 @@ -# Steem faucet +# Steem Faucet + +A web application for Steem account registration and management. + +## Prerequisites + +- Node.js >= 20 +- pnpm (package manager) +- MySQL database +- SMTP server (for email sending) +- Twilio account (for SMS verification, Deprecated) + +## Installation + +1. Clone the repository: +```bash +git clone https://github.com/steemit/faucet.git +cd faucet +``` + +2. Install dependencies: +```bash +pnpm install +``` + +## Database Setup + +### Initialize Database + +Set up and run migrations using Sequelize CLI: + +```bash +pnpm run db:migrate +``` + +The migration command uses the `DATABASE_URL` environment variable from your `.env` file. + +**Note**: If your local database server does not support SSL, you can modify the `ssl` option in `db/config/config.json` to set `rejectUnauthorized: false` for the `local` environment. + +### Seed Database + +To seed the database with initial data: + +```bash +env $(tr "\\n" " " < .env) sequelize-cli db:seed:all --config db/config/config.json --migrations-path db/migrations --seeders-path db/seeders --models-path db/models +``` + +Seed data can be added at: `db/seeders/` + +### Reset Database + +To start fresh (⚠️ **Warning**: This will delete all data): + +```bash +env $(tr "\\n" " " < .env) sequelize-cli db:migrate:undo:all --config db/config/config.json --migrations-path db/migrations --seeders-path db/seeders --models-path db/models +``` + +#### Example One-liner + +Reset and reinitialize the database: + +```bash +env $(tr "\\n" " " < .env) sequelize-cli db:migrate:undo:all --config db/config/config.json --migrations-path db/migrations --seeders-path db/seeders --models-path db/models && pnpm run db:migrate && env $(tr "\\n" " " < .env) sequelize-cli db:seed:all --config db/config/config.json --migrations-path db/migrations --seeders-path db/seeders --models-path db/models +``` + +## Configuration + +1. Copy `.env.example` to `.env`: +```bash +cp .env.example .env +``` + +2. Edit `.env` with your configuration values. See [Environment Variables](#environment-variables) section below for details. ## Environment Variables +### Database Configuration + +- **`DATABASE_URL`** (required) + - MySQL connection string + - Format: `mysql://username:password@hostname:port/database` + - Example: `mysql://root:password@localhost:3306/faucet` + +- **`DATABASE_EXPIRY`** (optional, default: `60`) + - Number of days to keep database records before cleanup + - Used for automatic cleanup of old actions and users + ### SMTP Configuration The following environment variables are required for email sending functionality: @@ -92,6 +175,281 @@ pnpm run test:smtp This will verify your SMTP connection and display the configuration being used. -### Other Environment Variables +### Steem/Blockchain Configuration + +- **`STEEMJS_URL`** (required) + - Steem RPC node URL + - Example: `https://api.steemit.com` + +- **`CONVEYOR_POSTING_WIF`** (required) + - Private posting key for conveyor account + +- **`CONVEYOR_USERNAME`** (required) + - Conveyor account username + +- **`CREATE_USER_SECRET`** (required) + - Secret key for create user API + +- **`CREATE_USER_URL`** (required) + - URL for create user API endpoint + - Example: `https://steemit.com/api/create_user` + +### Application Configuration + +- **`PORT`** (optional, default: `3001`) + - Port number for the HTTP server + +- **`NODE_ENV`** (optional, default: `development`) + - Environment mode: `development`, `production`, or `staging` + +- **`LOG_LEVEL`** (optional, default: `info`) + - Logging level: `debug`, `info`, `warn`, `error` + +- **`JWT_SECRET`** (required) + - Secret key for JWT token signing + +- **`DEFAULT_REDIRECT_URI`** (required) + - Default redirect URI after account creation + - Example: `https://steemit.com/login.html#account={{username}}` + +### Client-Side Configuration + +These variables are exposed to the client-side React application: + +- **`TURNSTILE_SWITCH`** (required) + - Enable/disable Cloudflare Turnstile captcha + - Values: `ON` or `OFF` + +- **`TURNSTILE_SITE_KEY`** (required) + - Cloudflare Turnstile site key + +- **`TURNSTILE_SECRET`** (required) + - Cloudflare Turnstile secret key (server-side only) + +- **`REACT_DISABLE_ACCOUNT_CREATION`** (required) + - Disable account creation in UI + - Values: `true` or `false` + +- **`PENDING_CLAIMED_ACCOUNTS_THRESHOLD`** (required) + - Threshold for pending claimed accounts + - Default: `100` + +- **`CREATOR_INFO`** (required) + - Creator account information (pipe-separated) + - Example: `steem|steemcurator01|steemcurator02` + +- **`GOOGLE_ANALYTICS_ID`** (optional) + - Google Analytics tracking ID + +### Newsletter Configuration + +- **`NEWSLETTER_URL`** (required) + - Newsletter subscription API URL + - Example: `https://newsletter.example.com/api/subscribe` + +- **`NEWSLETTER_LIST`** (required) + - Newsletter list identifier + - Example: `steem-faucet-users` + +### Other Configuration + +- **`DEBUG_MODE`** (optional) + - Enable debug mode (mocks external services) + - Set to any value to enable + +## Running the Application + +### Development Mode + +Build the frontend and start the development server: + +```bash +pnpm run build-dev +pnpm run start-dev +``` + +Or use the one-liner: + +```bash +env $(tr "\\n" " " < .env) pnpm run start-dev +``` + +The development server includes: +- Hot module replacement (HMR) +- Webpack dev middleware +- Automatic rebuilds on file changes +- Pretty-printed logs with `pino-pretty` + +### Production Mode + +1. Build the frontend: +```bash +pnpm run build +``` + +2. Start the server: +```bash +NODE_ENV=production pnpm start +``` + +## Docker + +A Dockerfile is provided for containerized deployment. + +### Building the Docker Image + +```bash +BRANCH="$(git rev-parse --abbrev-ref HEAD)" +docker build -t="$USER/faucet:$BRANCH" . +``` + +### Running the Docker Container + +```bash +docker run -it -p 3000:3001 --env-file=.env "$USER/faucet:$BRANCH" +``` + +**Note**: The Dockerfile exposes port 3001 internally, but you can map it to any external port (e.g., 3000) using the `-p` flag. + +**Important**: When running the Docker image locally, you may need to bind your MySQL server to not only localhost but also the IP used in Docker's network. You can then specify this IP in `DATABASE_URL`. + +### GitHub Actions CI/CD + +The project includes GitHub Actions workflows for automated testing and Docker image building. + +#### PR Testing + +When a pull request is created or updated, the `pnpm test` command will automatically run to ensure code quality. + +#### Docker Build and Push + +When code is pushed to the `master` branch, a Docker image will be automatically built and pushed to Docker Hub with two tags: +- `latest` - Always points to the latest master branch build +- `latest-{commit_sha}` - Tagged with the first 7 characters of the commit SHA (e.g., `latest-abc1234`) + +**Setup Docker Hub Secrets** + +To enable automatic Docker image pushing, you need to configure the following secrets in your GitHub repository: + +1. Go to your repository on GitHub +2. Navigate to **Settings** → **Secrets and variables** → **Actions** +3. Add the following secrets: + - `DOCKER_HUB_USERNAME`: Your Docker Hub username + - `DOCKER_HUB_TOKEN`: Your Docker Hub access token (not your password) + +To create a Docker Hub access token: +1. Log in to [Docker Hub](https://hub.docker.com/) +2. Go to **Account Settings** → **Security** +3. Click **New Access Token** +4. Give it a name (e.g., "GitHub Actions") and set appropriate permissions +5. Copy the token and add it as `DOCKER_HUB_TOKEN` secret in GitHub + +The Docker image will be pushed to: `{DOCKER_HUB_USERNAME}/faucet:latest` and `{DOCKER_HUB_USERNAME}/faucet:latest-{commit_sha}` + +## Testing + +The test suite includes linting, unit tests, and integration tests: + +```bash +pnpm test +``` + +This command runs: +1. ESLint static analysis (`pnpm run lint`) +2. Jest unit and integration tests (`pnpm run jest`) + +**Note**: You need to supply dummy values for required environment variables. Use the `.env.example` file: + +```bash +env $(grep -v '^#' .env.example | grep -v '^$' | tr "\\n" " ") pnpm test +``` + +### Individual Test Commands + +- Run linting only: +```bash +pnpm run lint +``` + +- Run tests only: +```bash +pnpm run jest +``` + +- Fix linting issues automatically: +```bash +pnpm run lint-fix +``` + +## Debugging + +### VSCode Configuration + +Add the following to `.vscode/launch.json` in the `configurations` array: + +```json +{ + "type": "node", + "request": "launch", + "name": "nodemon", + "runtimeExecutable": "${workspaceRoot}/node_modules/nodemon/bin/nodemon.js", + "program": "${workspaceFolder}/bin/www", + "restart": true, + "sourceMaps": true, + "outFiles": [], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "args": [ + "--ignore", + "src", + "|", + "bunyan", + "-o", + "short" + ], + "envFile": "${workspaceFolder}/.env" +} +``` + +## Project Structure + +``` +faucet/ +├── bin/ # Server entry point +├── db/ # Database models, migrations, seeders +│ ├── config/ # Sequelize configuration +│ ├── migrations/ # Database migrations +│ ├── models/ # Sequelize models +│ └── seeders/ # Database seeders +├── helpers/ # Utility functions and helpers +├── public/ # Static assets (CSS, images, etc.) +├── routes/ # Express routes +├── src/ # React frontend source code +│ ├── components/ # React components +│ ├── containers/ # React containers +│ ├── features/ # Feature modules +│ ├── locales/ # i18n translation files +│ └── utils/ # Frontend utilities +├── views/ # Handlebars templates +├── webpack/ # Webpack configuration +└── app.js # Express application setup +``` + +## Features + +- User account registration with email/SMS verification +- Cloudflare Turnstile captcha integration +- IP-based geolocation using MaxMind GeoIP2 +- Automatic database cleanup of old records +- Integration with Steem blockchain for account creation +- Newsletter subscription support +- Activity tracking and analytics +- Multi-language support (i18n) + +## License + +MIT + +## Support -See `.env.example` for a complete list of all environment variables. +For issues and questions, please visit: https://github.com/steemit/faucet/issues