Some checks failed
Docker Build / build-and-push-image (push) Failing after 18s
Adds an authentication layer in front of the bot handlers : - Auth handler on the principal bot (@arcodange_factory_bot, slug factory) parses /start, /auth <code>, /whoami, /logout. On a successful /auth, the message containing the code is best-effort deleted from the user's chat (replay defense). - Redis-backed sessions (key tg-gw:auth:<from.id>, TTL 24h, configurable via AUTH_SESSION_TTL). Constant-time secret compare via crypto/subtle. - ALLOWED_USERS env (CSV of Telegram user IDs) — silent-drops anyone not in the list before the auth gate runs. - New per-bot field 'requireAuth' (pointer-bool). Default = true (secure by default). Auto-forced to false for handler=auth (chicken-and-egg). - Server gates: allowlist first, then requireAuth before handler dispatch. - Fail-at-startup if a bot is configured with handler=auth or requireAuth: true while AUTH_SECRET is unset. Design: factory/docs/adr/20260509-telegram-gateway-auth.md (in factory PR). User docs: AUTH.md (new), HOWTO_ADD_BOT.md (Cas 2 updated for default true and gated flow). New deps: github.com/redis/go-redis/v9. Refs ~/.claude/plans/pour-les-notifications-on-inherited-seal.md § Phase 1.5.
75 lines
2.0 KiB
Go
75 lines
2.0 KiB
Go
package main
|
|
|
|
type Update struct {
|
|
UpdateID int64 `json:"update_id"`
|
|
Message *Message `json:"message,omitempty"`
|
|
EditedMessage *Message `json:"edited_message,omitempty"`
|
|
CallbackQuery *CallbackQuery `json:"callback_query,omitempty"`
|
|
}
|
|
|
|
type Message struct {
|
|
MessageID int64 `json:"message_id"`
|
|
From *User `json:"from,omitempty"`
|
|
Chat Chat `json:"chat"`
|
|
Date int64 `json:"date,omitempty"`
|
|
Text string `json:"text,omitempty"`
|
|
}
|
|
|
|
type Chat struct {
|
|
ID int64 `json:"id"`
|
|
Type string `json:"type,omitempty"`
|
|
}
|
|
|
|
type User struct {
|
|
ID int64 `json:"id"`
|
|
IsBot bool `json:"is_bot,omitempty"`
|
|
Username string `json:"username,omitempty"`
|
|
FirstName string `json:"first_name,omitempty"`
|
|
}
|
|
|
|
type CallbackQuery struct {
|
|
ID string `json:"id"`
|
|
From *User `json:"from,omitempty"`
|
|
Message *Message `json:"message,omitempty"`
|
|
Data string `json:"data,omitempty"`
|
|
}
|
|
|
|
func (u Update) ChatID() (int64, bool) {
|
|
switch {
|
|
case u.Message != nil:
|
|
return u.Message.Chat.ID, true
|
|
case u.EditedMessage != nil:
|
|
return u.EditedMessage.Chat.ID, true
|
|
case u.CallbackQuery != nil && u.CallbackQuery.Message != nil:
|
|
return u.CallbackQuery.Message.Chat.ID, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// UserID extracts the Telegram user ID (`from.id`) from whichever sub-payload
|
|
// is set. Used by the auth layer (factory bot session, requireAuth gate, allowlist).
|
|
// See factory/docs/adr/20260509-telegram-gateway-auth.md.
|
|
func (u Update) UserID() (int64, bool) {
|
|
switch {
|
|
case u.Message != nil && u.Message.From != nil:
|
|
return u.Message.From.ID, true
|
|
case u.EditedMessage != nil && u.EditedMessage.From != nil:
|
|
return u.EditedMessage.From.ID, true
|
|
case u.CallbackQuery != nil && u.CallbackQuery.From != nil:
|
|
return u.CallbackQuery.From.ID, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
func (u Update) Text() string {
|
|
switch {
|
|
case u.Message != nil:
|
|
return u.Message.Text
|
|
case u.EditedMessage != nil:
|
|
return u.EditedMessage.Text
|
|
case u.CallbackQuery != nil:
|
|
return u.CallbackQuery.Data
|
|
}
|
|
return ""
|
|
}
|