feat: sync Telegram Login OIDC provider
This commit is contained in:
parent
30774f8c39
commit
ebead9e98c
63 changed files with 11374 additions and 37 deletions
112
internal/domain/telegram_login_test.go
Normal file
112
internal/domain/telegram_login_test.go
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestValidateTelegramLoginScopes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
scopes []TelegramLoginScope
|
||||
alg TelegramLoginSigningAlgorithm
|
||||
valid bool
|
||||
}{
|
||||
{name: "rs profile phone", scopes: []TelegramLoginScope{TelegramLoginScopeOpenID, TelegramLoginScopeProfile, TelegramLoginScopePhone}, alg: TelegramLoginSigningRS256, valid: true},
|
||||
{name: "missing openid", scopes: []TelegramLoginScope{TelegramLoginScopeProfile}, alg: TelegramLoginSigningRS256},
|
||||
{name: "duplicate", scopes: []TelegramLoginScope{TelegramLoginScopeOpenID, TelegramLoginScopeOpenID}, alg: TelegramLoginSigningRS256},
|
||||
{name: "unknown", scopes: []TelegramLoginScope{TelegramLoginScopeOpenID, "admin"}, alg: TelegramLoginSigningRS256},
|
||||
{name: "eddsa openid", scopes: []TelegramLoginScope{TelegramLoginScopeOpenID}, alg: TelegramLoginSigningEdDSA, valid: true},
|
||||
{name: "eddsa profile forbidden", scopes: []TelegramLoginScope{TelegramLoginScopeOpenID, TelegramLoginScopeProfile}, alg: TelegramLoginSigningEdDSA},
|
||||
{name: "es256k phone forbidden", scopes: []TelegramLoginScope{TelegramLoginScopeOpenID, TelegramLoginScopePhone}, alg: TelegramLoginSigningES256K},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := ValidateTelegramLoginScopes(test.scopes, test.alg)
|
||||
if (err == nil) != test.valid {
|
||||
t.Fatalf("ValidateTelegramLoginScopes() error = %v, valid = %v", err, test.valid)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTelegramLoginRequestTransitions(t *testing.T) {
|
||||
for _, terminal := range []TelegramLoginRequestState{
|
||||
TelegramLoginRequestApproved,
|
||||
TelegramLoginRequestDeclined,
|
||||
TelegramLoginRequestExpired,
|
||||
} {
|
||||
if !CanTransitionTelegramLoginRequest(TelegramLoginRequestPending, terminal) {
|
||||
t.Fatalf("pending -> %s must be valid", terminal)
|
||||
}
|
||||
if CanTransitionTelegramLoginRequest(terminal, TelegramLoginRequestPending) {
|
||||
t.Fatalf("%s -> pending must be forbidden", terminal)
|
||||
}
|
||||
}
|
||||
if CanTransitionTelegramLoginRequest(TelegramLoginRequestApproved, TelegramLoginRequestDeclined) {
|
||||
t.Fatal("approved -> declined must be forbidden")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTelegramLoginRequestSourceShapeMatrix(t *testing.T) {
|
||||
now := time.Unix(1_780_000_000, 0).UTC()
|
||||
base := TelegramLoginRequest{
|
||||
RequestTokenHash: make([]byte, 32), BrowserTokenHash: make([]byte, 32),
|
||||
BotUserID: 9001, ClientID: "9001", SigningAlgorithm: TelegramLoginSigningRS256,
|
||||
Source: TelegramLoginRequestWeb, ResponseType: "code", RedirectURI: "https://rp.example/callback",
|
||||
Origin: "https://rp.example", Domain: "rp.example", Scopes: []TelegramLoginScope{TelegramLoginScopeOpenID},
|
||||
CodeChallenge: strings.Repeat("A", 43), CodeChallengeMethod: "S256",
|
||||
Browser: "Firefox", Platform: "Windows", IP: "192.0.2.1", Region: "Test",
|
||||
Status: TelegramLoginRequestPending, CreatedAt: now, ExpiresAt: now.Add(5 * time.Minute),
|
||||
}
|
||||
if err := base.Validate(); err != nil {
|
||||
t.Fatalf("valid web request: %v", err)
|
||||
}
|
||||
invalid := []struct {
|
||||
name string
|
||||
mutate func(*TelegramLoginRequest)
|
||||
}{
|
||||
{name: "web post message", mutate: func(r *TelegramLoginRequest) {
|
||||
r.ResponseType = "post_message"
|
||||
r.CodeChallenge = ""
|
||||
r.CodeChallengeMethod = ""
|
||||
}},
|
||||
{name: "javascript code", mutate: func(r *TelegramLoginRequest) { r.Source = TelegramLoginRequestJavaScript }},
|
||||
{name: "message button code", mutate: func(r *TelegramLoginRequest) { r.Source = TelegramLoginRequestMessageButton }},
|
||||
{name: "web app flag", mutate: func(r *TelegramLoginRequest) { r.IsApp = true; r.VerifiedAppName = "Forged" }},
|
||||
{name: "web missing origin", mutate: func(r *TelegramLoginRequest) { r.Origin = "" }},
|
||||
}
|
||||
for _, tc := range invalid {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
request := base.Clone()
|
||||
tc.mutate(&request)
|
||||
if err := request.Validate(); err == nil {
|
||||
t.Fatal("forbidden source shape was accepted")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
native := base.Clone()
|
||||
native.Source, native.Origin, native.Domain = TelegramLoginRequestNative, "", "dev.bedolaga.demo"
|
||||
native.IsApp, native.VerifiedAppName = true, "Bedolaga"
|
||||
if err := native.Validate(); err != nil {
|
||||
t.Fatalf("valid native request: %v", err)
|
||||
}
|
||||
native.IsApp = false
|
||||
if err := native.Validate(); err == nil {
|
||||
t.Fatal("native request without verified app state was accepted")
|
||||
}
|
||||
|
||||
mini := base.Clone()
|
||||
mini.Source, mini.ResponseType = TelegramLoginRequestMiniApp, "post_message"
|
||||
mini.CodeChallenge, mini.CodeChallengeMethod = "", ""
|
||||
mini.RedirectURI, mini.InAppOrigin = "https://rp.example/", mini.Origin
|
||||
if err := mini.Validate(); err != nil {
|
||||
t.Fatalf("valid Mini App request: %v", err)
|
||||
}
|
||||
mini.InAppOrigin = "https://other.example"
|
||||
if err := mini.Validate(); err == nil {
|
||||
t.Fatal("Mini App origin mismatch was accepted")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue