Documentation
¶
Overview ¶
Package twofa generates and verifies TOTP secrets for the CSuit apps.
Index ¶
- Constants
- Variables
- func CallbackTenant(data string) (string, bool)
- func CheckEmailCode(tenant string, userID int64, code string) (bool, error)
- func ClearDone(sessionKey string)
- func DiscardEmailCode(tenant string, userID int64)
- func Done(sessionKey string) (map[Method]bool, error)
- func HandleCallback(data string, chatID int64) (handled, approved, accepted bool)
- func MarkDone(sessionKey string, m Method) error
- func MarkReauth(tenant string, userID int64, m Method) error
- func NewEmailCode(tenant string, userID int64) (string, error)
- func NewSecret(issuer, account string) (string, error)
- func PollApproval(token, secret string) (status string, userID int64)
- func QRDataURL(issuer, secret, account string) (string, error)
- func StartApproval(ctx context.Context, bot *telegram.Bot, tenant string, userID, chatID int64, ...) (token, secret string, err error)
- func StartApprovalWith(ctx context.Context, ...) (token, secret string, err error)
- func TakeReauth(tenant string, userID int64, m Method) (bool, error)
- func Verify(secret, code string) bool
- func VerifyStep(secret, code string, now time.Time) (int64, bool)
- type Method
- type Prefs
- func (p Prefs) Enabled(totpOn, telegramLinked bool) []Method
- func (p Prefs) Encode() string
- func (p Prefs) NeedsStep(v Via, enabled []Method) bool
- func (p Prefs) ProofSatisfied(tenant string, userID int64, enabled []Method, totpOK bool, proven ...Method) (bool, error)
- func (p Prefs) Remaining(enabled []Method, done map[Method]bool) []Method
- func (p Prefs) Satisfied(enabled []Method, done map[Method]bool) bool
- func (p Prefs) SkipsFor(viaPasskey bool, enabled []Method) bool
- type Texts
- type Via
Constants ¶
const CallbackPrefix = "tg2fa:"
CallbackPrefix starts the callback data of the approval buttons; a bot hands any callback that starts with it to HandleCallback. The data is tg2fa:<tenant>:<token>:<y|n>, so a shared bot's hub can find the tenant that asked, the same way it does for sign-in buttons.
Variables ¶
var ErrEmailCooldown = errors.New("twofa: an email code was sent a moment ago")
var (
ErrNoRedis = errors.New("twofa: redis unavailable")
)
Functions ¶
func CallbackTenant ¶ added in v1.8.0
CallbackTenant returns the tenant named in an approval button's data, for a hub that has to pass the press on to the tenant that asked.
func CheckEmailCode ¶ added in v1.8.0
CheckEmailCode reports whether the code matches the one last sent, and uses it up when it does. After five wrong tries the code is gone.
func DiscardEmailCode ¶ added in v1.8.0
DiscardEmailCode forgets a code that could not be delivered.
func HandleCallback ¶ added in v1.8.0
HandleCallback is what a bot calls with the data of a pressed button. handled is false for callbacks that are not approval buttons. approved is the person's answer; accepted is false when the approval was already answered, expired or pressed from another chat.
func MarkDone ¶ added in v1.8.0
MarkDone remembers that a method was completed for one sign-in in progress (sessionKey is the app's own pending-2FA token). It is how "require all methods" carries progress from one step to the next.
func MarkReauth ¶ added in v1.8.0
MarkReauth records that a signed-in user just proved a method for a sensitive action (an approval pressed in Telegram, or an emailed code). It lasts two minutes and is used up by the first TakeReauth of the same method.
func NewEmailCode ¶ added in v1.8.0
NewEmailCode makes a six digit code for the person and remembers only its hash for ten minutes. A new code replaces the old one; asking again within thirty seconds returns ErrEmailCooldown. The caller emails the code and, when that fails, calls DiscardEmailCode so the person can ask again at once.
func PollApproval ¶ added in v1.8.0
PollApproval is called by the waiting page. An approved answer is returned once and then forgotten.
func QRDataURL ¶
QRDataURL renders the setup QR code for an existing base32 secret as a data:image/png URL. The secret is base32-decoded first so the code encodes the same secret that Verify checks against.
func StartApproval ¶ added in v1.8.0
func StartApproval(ctx context.Context, bot *telegram.Bot, tenant string, userID, chatID int64, tx Texts) (token, secret string, err error)
StartApproval records a pending approval for the person and sends them the message with its two buttons. The returned secret is for the page that is waiting: only its hash is stored, so a leaked button cannot sign anyone in.
func StartApprovalWith ¶ added in v1.8.0
func StartApprovalWith(ctx context.Context, send func(ctx context.Context, chat, text string, buttons []telegram.Button) error, tenant string, userID, chatID int64, tx Texts) (token, secret string, err error)
StartApprovalWith is StartApproval for callers that deliver the buttons through something other than a bot they hold, such as a relay.
func TakeReauth ¶ added in v1.8.0
TakeReauth reports whether a proof from MarkReauth is waiting, and uses it up.
func VerifyStep ¶ added in v1.2.4
VerifyStep checks a code like Verify and also returns the 30-second step it matched. Store the step per user and accept only a larger one next time, so a code cannot be used twice inside its validity window.
Types ¶
type Prefs ¶ added in v1.8.0
type Prefs struct {
Telegram bool `json:"telegram,omitempty"`
Email bool `json:"email,omitempty"`
All bool `json:"all,omitempty"`
PasskeySkips bool `json:"passkey_skips,omitempty"`
MagicSkips bool `json:"magic_skips,omitempty"`
TelegramSkips bool `json:"telegram_skips,omitempty"`
}
Prefs is what a person chose on their 2FA page besides which methods are switched on: whether every enabled method is required or any one will do, whether a passkey sign-in skips 2FA, and whether Telegram approval is on. It is stored as one small JSON string next to the account.
func ParsePrefs ¶ added in v1.8.0
func (Prefs) Enabled ¶ added in v1.8.0
Enabled lists the methods that apply to this account: the authenticator when it is set up, Telegram when the person turned it on and has a chat linked, and email when the person turned it on (every account has an address).
func (Prefs) NeedsStep ¶ added in v1.8.0
NeedsStep reports whether a sign-in by this route still needs a 2FA step. A magic link proves the email method and a Telegram sign-in proves the Telegram method, so each counts as that method being done; the person's own "skip 2FA for this route" choice is honoured for passkey, magic link and Telegram, never for a password or a password reset.
func (Prefs) ProofSatisfied ¶ added in v1.8.0
func (p Prefs) ProofSatisfied(tenant string, userID int64, enabled []Method, totpOK bool, proven ...Method) (bool, error)
ProofSatisfied decides a sensitive-action check for a signed-in person. totpOK says whether a valid authenticator or recovery code came with the request, and proven lists methods already checked in this request. The other methods are proven earlier, on the page, and left a proof that is used up here. In "all" mode nothing is used up until the code is right.