Initial commit
This commit is contained in:
38
Dockerfile
Normal file
38
Dockerfile
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
# Build stage
|
||||||
|
FROM golang:1.21-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy go mod files
|
||||||
|
COPY go.mod go.sum* ./
|
||||||
|
|
||||||
|
# Download dependencies
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY main.go .
|
||||||
|
|
||||||
|
# Build the binary
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o middleware main.go
|
||||||
|
|
||||||
|
# Final stage
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
# Add ca-certificates for HTTPS requests
|
||||||
|
RUN apk --no-cache add ca-certificates tzdata
|
||||||
|
|
||||||
|
WORKDIR /root/
|
||||||
|
|
||||||
|
# Copy the binary from builder stage
|
||||||
|
COPY --from=builder /app/middleware .
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
|
||||||
|
|
||||||
|
# Run the binary
|
||||||
|
CMD ["./middleware"]
|
||||||
54
Makefile
Normal file
54
Makefile
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
.PHONY: build run test clean docker-build docker-run help
|
||||||
|
|
||||||
|
BINARY_NAME=middleware
|
||||||
|
DOCKER_IMAGE=slack-to-ntfy
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
help:
|
||||||
|
@echo "Available targets:"
|
||||||
|
@echo " build - Build the Go binary"
|
||||||
|
@echo " run - Run the application locally"
|
||||||
|
@echo " test - Run tests"
|
||||||
|
@echo " clean - Clean build artifacts"
|
||||||
|
@echo " docker-build - Build Docker image"
|
||||||
|
@echo " docker-run - Run with Docker Compose"
|
||||||
|
@echo " docker-stop - Stop Docker Compose"
|
||||||
|
@echo " logs - Show Docker logs"
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -o $(BINARY_NAME) main.go
|
||||||
|
|
||||||
|
run: build
|
||||||
|
./$(BINARY_NAME)
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test -v ./...
|
||||||
|
|
||||||
|
clean:
|
||||||
|
go clean
|
||||||
|
rm -f $(BINARY_NAME)
|
||||||
|
|
||||||
|
docker-build:
|
||||||
|
docker build -t $(DOCKER_IMAGE) .
|
||||||
|
|
||||||
|
docker-run:
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
docker-stop:
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
logs:
|
||||||
|
docker compose logs -f
|
||||||
|
|
||||||
|
# Development helpers
|
||||||
|
fmt:
|
||||||
|
go fmt ./...
|
||||||
|
|
||||||
|
vet:
|
||||||
|
go vet ./...
|
||||||
|
|
||||||
|
mod-tidy:
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
|
deps: mod-tidy
|
||||||
|
go mod download
|
||||||
78
README.md
Normal file
78
README.md
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# Slack to ntfy Middleware
|
||||||
|
|
||||||
|
A lightweight Go service that acts as a middleware between Slack webhooks and ntfy servers, with Bearer token authentication and basic authentication support.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- ✅ Parses Slack webhook format
|
||||||
|
- ✅ Forwards alerts to self-hosted ntfy servers
|
||||||
|
- ✅ Bearer token authentication support
|
||||||
|
- ✅ Health check endpoint
|
||||||
|
- ✅ Lightweight Docker container (~8MB)
|
||||||
|
- ✅ High performance and low resource usage
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
1. **Configure the service**:
|
||||||
|
```bash
|
||||||
|
# Edit docker-compose.yml and set:
|
||||||
|
# - NTFY_BASE_URL=https://your-ntfy-server.com
|
||||||
|
# - NTFY_TOKEN=tk_your_bearer_token
|
||||||
|
# OR
|
||||||
|
# - NTFY_USERNAME=your_username
|
||||||
|
# - NTFY_PASSWORD=your_password
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Run the service**:
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Configure Slack**:
|
||||||
|
- Go to Slack Integrations → Incoming Webhooks
|
||||||
|
- Add new webhook
|
||||||
|
- Webhook URL: `http://your-server-ip:8080/your-topic-name`
|
||||||
|
|
||||||
|
4. **Test the service**:
|
||||||
|
```bash
|
||||||
|
# Test webhook
|
||||||
|
curl -X POST http://localhost:8080/test-topic \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"text": "Test alert from Slack to ntfy"}'
|
||||||
|
|
||||||
|
# Check health
|
||||||
|
curl http://localhost:8080/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
| Environment Variable | Default | Description |
|
||||||
|
|---------------------|---------|-------------|
|
||||||
|
| `NTFY_BASE_URL` | `https://ntfy.sh` | Your ntfy server URL (without topic) |
|
||||||
|
| `NTFY_TOKEN` | `""` | Bearer token for ntfy authentication |
|
||||||
|
| `NTFY_USERNAME` | `""` | Username for ntfy basic authentication |
|
||||||
|
| `NTFY_PASSWORD` | `""` | Password for ntfy basic authentication |
|
||||||
|
| `BIND_ADDRESS` | `0.0.0.0` | Interface to bind to |
|
||||||
|
| `BIND_PORT` | `8080` | Port to listen on |
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Build locally
|
||||||
|
```bash
|
||||||
|
go build -o middleware main.go
|
||||||
|
./middleware
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Docker image
|
||||||
|
```bash
|
||||||
|
docker build -t slack-to-ntfy .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run tests
|
||||||
|
```bash
|
||||||
|
go test ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License
|
||||||
46
docker-compose.yml
Normal file
46
docker-compose.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
slack-to-ntfy:
|
||||||
|
build: .
|
||||||
|
container_name: slack-to-ntfy
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
environment:
|
||||||
|
# Replace with your ntfy server URL (without topic path)
|
||||||
|
- NTFY_BASE_URL=https://ntfy.dangerzone.dev
|
||||||
|
|
||||||
|
# For token-based authentication, uncomment and replace with your ntfy Bearer token (e.g., tk_xxxx)
|
||||||
|
- NTFY_TOKEN=tk_7hdlipcf02hsaslgmav70ruzkurcp
|
||||||
|
|
||||||
|
# For username/password authentication, uncomment and replace with your ntfy credentials
|
||||||
|
# - NTFY_USERNAME=your_username
|
||||||
|
# - NTFY_PASSWORD=your_password
|
||||||
|
|
||||||
|
# Bind configuration
|
||||||
|
- BIND_ADDRESS=0.0.0.0
|
||||||
|
- BIND_PORT=8080
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# Optional: Resource limits
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 32M
|
||||||
|
cpus: '0.1'
|
||||||
|
reservations:
|
||||||
|
memory: 16M
|
||||||
|
cpus: '0.05'
|
||||||
|
|
||||||
|
# Health check using the built-in endpoint
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
|
# Optional: Create a custom network
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
name: slack-ntfy-middleware
|
||||||
232
main.go
Normal file
232
main.go
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SlackWebhookPayload represents the incoming Slack webhook format
|
||||||
|
type SlackWebhookPayload struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
Channel string `json:"channel,omitempty"`
|
||||||
|
IconEmoji string `json:"icon_emoji,omitempty"`
|
||||||
|
Attachments []struct {
|
||||||
|
Color string `json:"color,omitempty"`
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
Footer string `json:"footer,omitempty"`
|
||||||
|
Timestamp int64 `json:"ts,omitempty"`
|
||||||
|
} `json:"attachments,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config holds the middleware configuration
|
||||||
|
type Config struct {
|
||||||
|
NtfyBaseURL string
|
||||||
|
NtfyToken string
|
||||||
|
NtfyUsername string
|
||||||
|
NtfyPassword string
|
||||||
|
BindAddress string
|
||||||
|
BindPort string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Middleware handles the webhook forwarding
|
||||||
|
type Middleware struct {
|
||||||
|
config Config
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMiddleware(config Config) *Middleware {
|
||||||
|
return &Middleware{
|
||||||
|
config: config,
|
||||||
|
client: &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractMessage extracts the alert message from various Slack webhook formats
|
||||||
|
func (m *Middleware) extractMessage(payload *SlackWebhookPayload) string {
|
||||||
|
// Primary message text
|
||||||
|
if payload.Text != "" {
|
||||||
|
return payload.Text
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check attachments for additional content
|
||||||
|
if len(payload.Attachments) > 0 {
|
||||||
|
var parts []string
|
||||||
|
|
||||||
|
for _, attachment := range payload.Attachments {
|
||||||
|
if attachment.Title != "" {
|
||||||
|
parts = append(parts, attachment.Title)
|
||||||
|
}
|
||||||
|
if attachment.Text != "" {
|
||||||
|
parts = append(parts, attachment.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(parts) > 0 {
|
||||||
|
return strings.Join(parts, "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Generic Message"
|
||||||
|
}
|
||||||
|
|
||||||
|
// forwardToNtfy sends the message to the ntfy server
|
||||||
|
func (m *Middleware) forwardToNtfy(topic, message string) error {
|
||||||
|
ntfyURL := fmt.Sprintf("%s/%s", strings.TrimRight(m.config.NtfyBaseURL, "/"), topic)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", ntfyURL, bytes.NewBufferString(message))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
|
req.Header.Set("User-Agent", "slack-to-ntfy/1.0")
|
||||||
|
|
||||||
|
if m.config.NtfyToken != "" {
|
||||||
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", m.config.NtfyToken))
|
||||||
|
} else if m.config.NtfyUsername != "" && m.config.NtfyPassword != "" {
|
||||||
|
req.SetBasicAuth(m.config.NtfyUsername, m.config.NtfyPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Title", "Slack to ntfy Alert")
|
||||||
|
req.Header.Set("Priority", "high")
|
||||||
|
req.Header.Set("Tags", "warning,computer")
|
||||||
|
|
||||||
|
resp, err := m.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to send request: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return fmt.Errorf("ntfy request failed with status %d: %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Successfully forwarded message to ntfy topic '%s'", topic)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// webhookHandler handles incoming Slack webhook requests
|
||||||
|
func (m *Middleware) webhookHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract topic from URL path
|
||||||
|
topic := strings.TrimPrefix(r.URL.Path, "/")
|
||||||
|
if topic == "" {
|
||||||
|
http.Error(w, "Topic is required in URL path", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean topic (remove any path traversal attempts)
|
||||||
|
topic = path.Clean(topic)
|
||||||
|
if strings.Contains(topic, "..") {
|
||||||
|
http.Error(w, "Invalid topic name", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read request body
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to read request body: %v", err)
|
||||||
|
http.Error(w, "Failed to read request", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var message string
|
||||||
|
|
||||||
|
// Try to parse as JSON (Slack webhook format)
|
||||||
|
var payload SlackWebhookPayload
|
||||||
|
if err := json.Unmarshal(body, &payload); err == nil {
|
||||||
|
message = m.extractMessage(&payload)
|
||||||
|
log.Printf("Received Slack webhook for topic '%s': %s", topic, message)
|
||||||
|
} else {
|
||||||
|
// Fallback to raw text
|
||||||
|
message = string(body)
|
||||||
|
if message == "" {
|
||||||
|
message = "Slack to ntfy Alert (no content)"
|
||||||
|
}
|
||||||
|
log.Printf("Received raw webhook for topic '%s': %s", topic, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward to ntfy
|
||||||
|
if err := m.forwardToNtfy(topic, message); err != nil {
|
||||||
|
log.Printf("Failed to forward to ntfy: %v", err)
|
||||||
|
http.Error(w, "Failed to forward alert", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return success response
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
response := map[string]string{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Alert forwarded to ntfy",
|
||||||
|
"topic": topic,
|
||||||
|
}
|
||||||
|
json.NewEncoder(w).Encode(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// healthHandler provides a health check endpoint
|
||||||
|
func (m *Middleware) healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
response := map[string]interface{}{
|
||||||
|
"status": "healthy",
|
||||||
|
"ntfy_url": m.config.NtfyBaseURL,
|
||||||
|
"auth_enabled": m.config.NtfyToken != "" || m.config.NtfyUsername != "",
|
||||||
|
"timestamp": time.Now().Unix(),
|
||||||
|
}
|
||||||
|
json.NewEncoder(w).Encode(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfig() Config {
|
||||||
|
return Config{
|
||||||
|
NtfyBaseURL: getEnv("NTFY_BASE_URL", "https://ntfy.sh"),
|
||||||
|
NtfyToken: getEnv("NTFY_TOKEN", ""),
|
||||||
|
NtfyUsername: getEnv("NTFY_USERNAME", ""),
|
||||||
|
NtfyPassword: getEnv("NTFY_PASSWORD", ""),
|
||||||
|
BindAddress: getEnv("BIND_ADDRESS", "0.0.0.0"),
|
||||||
|
BindPort: getEnv("BIND_PORT", "8080"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEnv(key, defaultValue string) string {
|
||||||
|
if value := os.Getenv(key); value != "" {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
config := loadConfig()
|
||||||
|
middleware := NewMiddleware(config)
|
||||||
|
|
||||||
|
// Setup routes
|
||||||
|
http.HandleFunc("/health", middleware.healthHandler)
|
||||||
|
http.HandleFunc("/", middleware.webhookHandler)
|
||||||
|
|
||||||
|
// Start server
|
||||||
|
bindAddr := fmt.Sprintf("%s:%s", config.BindAddress, config.BindPort)
|
||||||
|
|
||||||
|
log.Printf("Starting Slack to ntfy middleware server")
|
||||||
|
log.Printf("Listening on: %s", bindAddr)
|
||||||
|
log.Printf("ntfy URL: %s", config.NtfyBaseURL)
|
||||||
|
log.Printf("Authentication: %t", config.NtfyToken != "" || config.NtfyUsername != "")
|
||||||
|
|
||||||
|
if err := http.ListenAndServe(bindAddr, nil); err != nil {
|
||||||
|
log.Fatalf("Server failed to start: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
26
scripts/build.sh
Executable file
26
scripts/build.sh
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🔨 Building Slack to ntfy middleware..."
|
||||||
|
|
||||||
|
# Build for different platforms
|
||||||
|
PLATFORMS="linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64"
|
||||||
|
OUTPUT_DIR="dist"
|
||||||
|
|
||||||
|
mkdir -p $OUTPUT_DIR
|
||||||
|
|
||||||
|
for platform in $PLATFORMS; do
|
||||||
|
OS=$(echo $platform | cut -d'/' -f1)
|
||||||
|
ARCH=$(echo $platform | cut -d'/' -f2)
|
||||||
|
|
||||||
|
OUTPUT_NAME="middleware-$OS-$ARCH"
|
||||||
|
if [ $OS = "windows" ]; then
|
||||||
|
OUTPUT_NAME="$OUTPUT_NAME.exe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building for $OS/$ARCH..."
|
||||||
|
CGO_ENABLED=0 GOOS=$OS GOARCH=$ARCH go build -a -installsuffix cgo -o $OUTPUT_DIR/$OUTPUT_NAME main.go
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "✅ Build complete! Binaries available in $OUTPUT_DIR/"
|
||||||
|
ls -la $OUTPUT_DIR/
|
||||||
56
scripts/setup.sh
Executable file
56
scripts/setup.sh
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "⚙️ Setting up Slack to ntfy middleware..."
|
||||||
|
|
||||||
|
# Check if Docker is installed
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
echo "❌ Docker is not installed. Please install Docker first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if Docker Compose is available
|
||||||
|
if ! docker compose version &> /dev/null; then
|
||||||
|
echo "❌ Docker Compose is not available. Please install Docker Compose."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Docker and Docker Compose are available"
|
||||||
|
|
||||||
|
# Prompt for configuration
|
||||||
|
echo
|
||||||
|
echo "📝 Please provide your ntfy server configuration:"
|
||||||
|
read -p "ntfy server URL (e.g., https://ntfy.example.com): " NTFY_URL
|
||||||
|
read -p "Bearer token (e.g., tk_xxxxx) [optional]: " NTFY_TOKEN
|
||||||
|
read -p "ntfy username (for basic auth) [optional]: " NTFY_USERNAME
|
||||||
|
read -p "ntfy password (for basic auth) [optional]: " NTFY_PASSWORD
|
||||||
|
|
||||||
|
# Update docker-compose.yml
|
||||||
|
if [ ! -z "$NTFY_URL" ]; then
|
||||||
|
sed -i '' "s|https://your-ntfy-server.com|$NTFY_URL|g" docker-compose.yml
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reset all auth lines to commented placeholders first to ensure a clean state
|
||||||
|
sed -i '' "s|^ - NTFY_TOKEN=.*| # - NTFY_TOKEN=tk_your_bearer_token_here|" docker-compose.yml
|
||||||
|
sed -i '' "s|^ - NTFY_USERNAME=.*| # - NTFY_USERNAME=your_username|" docker-compose.yml
|
||||||
|
sed -i '' "s|^ - NTFY_PASSWORD=.*| # - NTFY_PASSWORD=your_password|" docker-compose.yml
|
||||||
|
|
||||||
|
if [ ! -z "$NTFY_TOKEN" ]; then
|
||||||
|
sed -i '' "s|^ # - NTFY_TOKEN=tk_your_bearer_token_here| - NTFY_TOKEN=$NTFY_TOKEN|" docker-compose.yml
|
||||||
|
elif [ ! -z "$NTFY_USERNAME" ] && [ ! -z "$NTFY_PASSWORD" ]; then
|
||||||
|
sed -i '' "s|^ # - NTFY_USERNAME=your_username| - NTFY_USERNAME=$NTFY_USERNAME|" docker-compose.yml
|
||||||
|
sed -i '' "s|^ # - NTFY_PASSWORD=your_password| - NTFY_PASSWORD=$NTFY_PASSWORD|" docker-compose.yml
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Configuration updated in docker-compose.yml"
|
||||||
|
|
||||||
|
# Build and start
|
||||||
|
echo "🐳 Building and starting the service..."
|
||||||
|
docker compose up -d --build
|
||||||
|
|
||||||
|
echo "✅ Service is starting up..."
|
||||||
|
echo
|
||||||
|
echo "Next steps:"
|
||||||
|
echo "1. Test the service: ./scripts/test.sh"
|
||||||
|
echo "2. Check logs: docker compose logs -f"
|
||||||
|
echo "3. Configure Slack webhook URL: http://your-server-ip:8080/your-topic-name"
|
||||||
39
scripts/test.sh
Executable file
39
scripts/test.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
MIDDLEWARE_URL="http://localhost:8080"
|
||||||
|
TEST_TOPIC="test-topic"
|
||||||
|
|
||||||
|
echo "🧪 Testing Slack to ntfy middleware..."
|
||||||
|
|
||||||
|
# Check if service is running
|
||||||
|
echo "Checking if middleware is running..."
|
||||||
|
if ! curl -s "$MIDDLEWARE_URL/health" > /dev/null; then
|
||||||
|
echo "❌ Middleware is not running on $MIDDLEWARE_URL"
|
||||||
|
echo "Please start it with: docker compose up -d"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Middleware is running"
|
||||||
|
|
||||||
|
# Test health endpoint
|
||||||
|
echo "Testing health endpoint..."
|
||||||
|
HEALTH_RESPONSE=$(curl -s "$MIDDLEWARE_URL/health")
|
||||||
|
echo "Health response: $HEALTH_RESPONSE"
|
||||||
|
|
||||||
|
# Test Slack webhook format
|
||||||
|
echo "Testing Slack webhook format..."
|
||||||
|
curl -X POST "$MIDDLEWARE_URL/$TEST_TOPIC" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"text": "🧪 Test alert from Slack to ntfy middleware test script"}' \
|
||||||
|
-w "\nHTTP Status: %{http_code}\n"
|
||||||
|
|
||||||
|
# Test plain text format
|
||||||
|
echo "Testing plain text format..."
|
||||||
|
curl -X POST "$MIDDLEWARE_URL/$TEST_TOPIC" \
|
||||||
|
-H 'Content-Type: text/plain' \
|
||||||
|
-d 'Plain text test alert' \
|
||||||
|
-w "\nHTTP Status: %{http_code}\n"
|
||||||
|
|
||||||
|
echo "✅ Tests completed!"
|
||||||
|
echo "Check your ntfy client to see if messages were delivered to topic: $TEST_TOPIC"
|
||||||
Reference in New Issue
Block a user