mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-15 04:53:00 +08:00
87 lines
3.1 KiB
Go
87 lines
3.1 KiB
Go
package application
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/matthewlu070111/smart-srun/core/internal/auth"
|
|
"github.com/matthewlu070111/smart-srun/core/internal/config"
|
|
"github.com/matthewlu070111/smart-srun/core/internal/domain"
|
|
)
|
|
|
|
func (a *Authenticator) verifySession(ctx context.Context, tx *auth.Transaction, p *attempt, report func(Phase), known *auth.Identity) Outcome {
|
|
return a.terminalChecks(ctx, p, func() (Outcome, bool) {
|
|
out := a.verifyOnce(ctx, tx, p, report, known)
|
|
known = nil // every later check asks whose session is on the line now
|
|
return out, retryableTerminal(out)
|
|
})
|
|
}
|
|
|
|
func retryableTerminal(out Outcome) bool {
|
|
if out.State != StateFailed {
|
|
return false
|
|
}
|
|
switch out.Code {
|
|
case domain.CodeTransportFailure, domain.CodeDNSFailure, domain.CodeDeadlineExceeded:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (a *Authenticator) verifyLogout(ctx context.Context, tx *auth.Transaction, p *attempt, identity string, report func(Phase)) Outcome {
|
|
return a.terminalChecks(ctx, p, func() (Outcome, bool) {
|
|
report(PhaseVerify)
|
|
after, err := tx.Online(ctx, p.username)
|
|
if changed := a.confirmUnchanged(ctx, p); changed != nil {
|
|
return p.failed(a, changed, domain.AuthUnknown, ""), false
|
|
}
|
|
if err != nil {
|
|
out := p.unconfirmed(a, "已发送登出请求,但无法确认这条线路是否已下线:"+userMessage(err), identity)
|
|
code, _ := domain.CodeOf(err)
|
|
return out, code == domain.CodeTransportFailure || code == domain.CodeDNSFailure || code == domain.CodeDeadlineExceeded
|
|
}
|
|
if !after.Present {
|
|
return p.wentOffline(a, "已登出"), false
|
|
}
|
|
out := p.failed(a, domain.Errorf(domain.CodeConflict, "网关接受了登出请求,但这条线路上仍有在线会话"), after.State(), after.Username)
|
|
return out, after.Username == identity
|
|
})
|
|
}
|
|
|
|
// Only confirmation is retried: this loop cannot send a password or unbind.
|
|
// Scheduled transitions use the same bounded confirmation as manual actions;
|
|
// an eventually consistent portal must not delay a switch by an entire normal
|
|
// maintenance interval. Ordinary maintenance retains its scheduler/backoff.
|
|
func (a *Authenticator) terminalChecks(ctx context.Context, p *attempt, check func() (Outcome, bool)) Outcome {
|
|
count := 1
|
|
if p.intent == auth.IntentManual || p.confirmTerminal {
|
|
count = max(1, min(config.MaxTerminalAttempts, p.checks.TerminalAttempts))
|
|
}
|
|
interval := time.Duration(max(1, min(config.MaxTerminalIntervalSeconds, p.checks.TerminalIntervalSeconds))) * time.Second
|
|
for index := 0; ; index++ {
|
|
if err := ctx.Err(); err != nil {
|
|
code, message := domain.CodeCancelled, "终态检查已取消"
|
|
if err == context.DeadlineExceeded {
|
|
code, message = domain.CodeDeadlineExceeded, "终态检查已超时"
|
|
}
|
|
return p.failed(a, domain.Errorf(code, "%s", message).Wrap(err), domain.AuthUnknown, "")
|
|
}
|
|
if index > 0 {
|
|
if err := a.confirmUnchanged(ctx, p); err != nil {
|
|
return p.failed(a, err, domain.AuthUnknown, "")
|
|
}
|
|
}
|
|
out, retry := check()
|
|
if !retry || index+1 >= count {
|
|
return out
|
|
}
|
|
timer := a.clock.NewTimerAt(a.clock.Now().Add(interval))
|
|
select {
|
|
case <-timer.C():
|
|
case <-ctx.Done():
|
|
}
|
|
timer.Stop()
|
|
}
|
|
}
|