diff --git a/internal/check/ExternalMigration.go b/internal/check/ExternalMigration.go index 02f1a52..76869e7 100644 --- a/internal/check/ExternalMigration.go +++ b/internal/check/ExternalMigration.go @@ -1,9 +1,16 @@ package check import ( + "crypto/hmac" + "crypto/sha512" + "fmt" "server_torii/internal/action" "server_torii/internal/config" "server_torii/internal/dataType" + "server_torii/internal/utils" + "strconv" + "strings" + "time" ) func ExternalMigration(reqData dataType.UserRequest, ruleSet *config.RuleSet, decision *action.Decision, sharedMem *dataType.SharedMemory) { @@ -12,10 +19,79 @@ func ExternalMigration(reqData dataType.UserRequest, ruleSet *config.RuleSet, de return } - if !verifyClearanceCookie(reqData, *ruleSet) { - decision.SetResponse(action.Done, []byte("EXTERNAL"), genSessionID(reqData, *ruleSet)) + if !verifyExternalMigrationClearanceCookie(reqData, *ruleSet) { + decision.SetResponse(action.Done, []byte("EXTERNAL"), genExternalMigrationSessionID(reqData, *ruleSet)) return } decision.Set(action.Continue) } + +func GenExternalMigrationClearance(reqData dataType.UserRequest, ruleSet config.RuleSet) []byte { + timeNow := time.Now().Unix() + mac := hmac.New(sha512.New, []byte(ruleSet.ExternalMigrationRule.SecretKey)) + mac.Write([]byte(fmt.Sprintf("%d%s%sEXTERNAL-CLEARANCE", timeNow, reqData.Host, utils.GetClearanceUserAgent(reqData.UserAgent)))) + return []byte(fmt.Sprintf("%s:%s", fmt.Sprintf("%d", time.Now().Unix()), fmt.Sprintf("%x", mac.Sum(nil)))) +} + +func verifyExternalMigrationClearanceCookie(reqData dataType.UserRequest, ruleSet config.RuleSet) bool { + if reqData.ToriiClearance == "" { + return false + } + parts := strings.Split(reqData.ToriiClearance, ":") + if len(parts) != 2 { + return false + } + timestamp := parts[0] + expectedHash := parts[1] + + timeNow := time.Now().Unix() + parsedTimestamp, err := strconv.ParseInt(timestamp, 10, 64) + if err != nil { + utils.LogError(reqData, "", fmt.Sprintf("Error parsing timestamp: %v", err)) + return false + } + + if timeNow-parsedTimestamp > ruleSet.ExternalMigrationRule.SessionTimeout { + return false + } + + mac := hmac.New(sha512.New, []byte(ruleSet.ExternalMigrationRule.SecretKey)) + mac.Write([]byte(fmt.Sprintf("%d%s%sEXTERNAL-CLEARANCE", parsedTimestamp, reqData.Host, utils.GetClearanceUserAgent(reqData.UserAgent)))) + computedHash := fmt.Sprintf("%x", mac.Sum(nil)) + + return hmac.Equal([]byte(computedHash), []byte(expectedHash)) + +} + +func genExternalMigrationSessionID(reqData dataType.UserRequest, ruleSet config.RuleSet) []byte { + timeNow := time.Now().Unix() + mac := hmac.New(sha512.New, []byte(ruleSet.ExternalMigrationRule.SecretKey)) + mac.Write([]byte(fmt.Sprintf("%d%s%sEXTERNAL-SESSION", timeNow, reqData.Host, utils.GetClearanceUserAgent(reqData.UserAgent)))) + return []byte(fmt.Sprintf("%s:%s", fmt.Sprintf("%d", time.Now().Unix()), fmt.Sprintf("%x", mac.Sum(nil)))) +} + +func verifyExternalMigrationSessionIDCookie(reqData dataType.UserRequest, ruleSet config.RuleSet) bool { + if reqData.ToriiSessionID == "" { + return false + } + parts := strings.Split(reqData.ToriiSessionID, ":") + if len(parts) != 2 { + return false + } + timestamp := parts[0] + expectedHash := parts[1] + + parsedTimestamp, err := strconv.ParseInt(timestamp, 10, 64) + if err != nil { + utils.LogError(reqData, "", fmt.Sprintf("Error parsing timestamp: %v", err)) + return false + } + + mac := hmac.New(sha512.New, []byte(ruleSet.ExternalMigrationRule.SecretKey)) + mac.Write([]byte(fmt.Sprintf("%d%s%sEXTERNAL-SESSION", parsedTimestamp, reqData.Host, utils.GetClearanceUserAgent(reqData.UserAgent)))) + computedHash := fmt.Sprintf("%x", mac.Sum(nil)) + + return hmac.Equal([]byte(computedHash), []byte(expectedHash)) + +} diff --git a/internal/server/checker.go b/internal/server/checker.go index a965d34..6e6ba2f 100644 --- a/internal/server/checker.go +++ b/internal/server/checker.go @@ -107,6 +107,11 @@ func CheckMain(w http.ResponseWriter, userRequestData dataType.UserRequest, rule return } + } else if bytes.Compare(decision.HTTPCode, []byte("EXTERNAL")) == 0 { + w.Header().Set("Set-Cookie", "__torii_sessionid="+string(decision.ResponseData)+"; Path=/; Max-Age=86400; Priority=High; HttpOnly; SameSite=Lax") + w.Header().Set("Location", ruleSet.ExternalMigrationRule.RedirectUrl+"?domain="+userRequestData.Host+"&session_id="+string(decision.ResponseData)+"&original_url="+userRequestData.Uri) + w.WriteHeader(http.StatusFound) + return } else { //should never happen utils.LogError(userRequestData, fmt.Sprintf("Error access in wrong state: %v", decision), "CheckMain")