Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
ROCKETCHAT_SERVER_URL=https://chat.yourcompany.com
ROCKETCHAT_BOT_USERNAME=geekbot
ROCKETCHAT_BOT_PASSWORD=your-password

# Alternative: read password from a file (avoids shell/env escaping issues)
# ROCKETCHAT_BOT_PASSWORD_FILE=/run/secrets/bot_password
# Auth method 1: Personal Access Token (recommended — no special char issues)
# Generate at: Account → Personal Access Tokens
ROCKETCHAT_BOT_TOKEN=
ROCKETCHAT_BOT_USER_ID=

# Auth method 2: Password (alternative if you don't use PAT)
# ROCKETCHAT_BOT_PASSWORD=your-password

ROCKETCHAT_MAIN_ADMIN=admin_username
STANDUP_DB_PATH=/data/standup-bot.db
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ cp .env.example .env
|----------|----------|---------|-------------|
| `ROCKETCHAT_SERVER_URL` | Yes | — | Rocket.Chat server URL |
| `ROCKETCHAT_BOT_USERNAME` | Yes | — | Bot account username |
| `ROCKETCHAT_BOT_PASSWORD` | One of | — | Bot account password (use if password has no special chars) |
| `ROCKETCHAT_BOT_PASSWORD_FILE` | One of | — | Path to file containing the bot password (avoids shell/env escaping) |
| `ROCKETCHAT_BOT_TOKEN` | One of | — | Personal Access Token (recommended — no special char issues) |
| `ROCKETCHAT_BOT_USER_ID` | One of | — | User ID for the PAT |
| `ROCKETCHAT_BOT_PASSWORD` | One of | — | Bot account password (alternative auth method) |
| `ROCKETCHAT_MAIN_ADMIN` | Yes | — | Rocket.Chat username of the main bot administrator |
| `STANDUP_DB_PATH` | No | `~/standup-bot.db` | Path to the SQLite database file |

Expand Down
2 changes: 1 addition & 1 deletion cmd/bot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func main() {
}
})

if err := client.Connect(cfg.BotUser, cfg.BotPass); err != nil {
if err := client.Connect(cfg.BotUser, cfg.BotPass, cfg.BotToken, cfg.BotUserID); err != nil {
log.Printf("Failed to connect: %v", err)
if strings.Contains(err.Error(), "authentication failed") {
log.Println("Auth failure is permanent — exiting to prevent Docker restart loop")
Expand Down
20 changes: 14 additions & 6 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import (
)

type Config struct {
ServerURL string
BotUser string
BotPass string
MainAdmin string
ServerURL string
BotUser string
BotPass string
BotToken string
BotUserID string
MainAdmin string
}

func Load() (*Config, error) {
Expand All @@ -29,6 +31,8 @@ func Load() (*Config, error) {
ServerURL: os.Getenv("ROCKETCHAT_SERVER_URL"),
BotUser: os.Getenv("ROCKETCHAT_BOT_USERNAME"),
BotPass: botPass,
BotToken: os.Getenv("ROCKETCHAT_BOT_TOKEN"),
BotUserID: os.Getenv("ROCKETCHAT_BOT_USER_ID"),
MainAdmin: os.Getenv("ROCKETCHAT_MAIN_ADMIN"),
}

Expand All @@ -38,8 +42,12 @@ func Load() (*Config, error) {
if cfg.BotUser == "" {
return nil, fmt.Errorf("ROCKETCHAT_BOT_USERNAME is required")
}
if cfg.BotPass == "" {
return nil, fmt.Errorf("ROCKETCHAT_BOT_PASSWORD is required")

hasToken := cfg.BotToken != "" && cfg.BotUserID != ""
hasPass := cfg.BotPass != ""

if !hasToken && !hasPass {
return nil, fmt.Errorf("either ROCKETCHAT_BOT_PASSWORD or (ROCKETCHAT_BOT_TOKEN + ROCKETCHAT_BOT_USER_ID) must be set")
}
if cfg.MainAdmin == "" {
return nil, fmt.Errorf("ROCKETCHAT_MAIN_ADMIN is required")
Expand Down
21 changes: 17 additions & 4 deletions internal/rocket/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type Client struct {
connected bool
user string
password string
token string
userID string
}

type MessageHandler func(msg IncomingMessage)
Expand All @@ -66,12 +68,14 @@ func New(serverURL string) (*Client, error) {
}, nil
}

func (c *Client) Connect(user, password string) error {
func (c *Client) Connect(user, password, token, userID string) error {
c.mu.Lock()
defer c.mu.Unlock()

c.user = user
c.password = password
c.token = token
c.userID = userID

log.Printf("Connecting to Rocket.Chat at %s", c.serverURL.String())

Expand All @@ -93,10 +97,19 @@ func (c *Client) connect() error {
return fmt.Errorf("realtime connect: %w", err)
}

creds := &models.UserCredentials{
Email: c.user,
Password: c.password,
var creds *models.UserCredentials
if c.token != "" && c.userID != "" {
creds = &models.UserCredentials{
ID: c.userID,
Token: c.token,
}
} else {
creds = &models.UserCredentials{
Email: c.user,
Password: c.password,
}
}

if _, err := rt.Login(creds); err != nil {
rt.Close()
return fmt.Errorf("realtime login: %w", err)
Expand Down
Loading