162 lines
4.7 KiB
Go
162 lines
4.7 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
msTokenURL = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
|
|
outlookMailURL = "https://outlook.office.com/api/v2.0/me/mailFolders/inbox/messages"
|
|
)
|
|
|
|
func main() {
|
|
clientID := "9e5f94bc-e8a4-4e73-b8be-63364c29d753"
|
|
refreshToken := "M.C502_SN1.0.U.-Crvsmbp5ATQIkZ3hocv9p7Z2X5!OXVJHdHa72LcvvI0vL89DBJ3O6CU!j07BU3A9kAJlFQcYVE*wmp!riMOJXBdeMvgB9xuF0duYbb8*M8qCnYGkX196K0z5CMhkHOOSahXbHkWN0cI685XA4z27rPYPOcGylHZdax1K0wF6N4kSxe*eoXn0dYL9wMPe1oC3vQ62B1EYECpaqqpfIKfKqhBpkbQ74up272uhiMvlRkYiD6ZCxL1aSeHg*aRiXGP4XfWWojKHN5rBqcXCXTRTGqw4r1Zij!RDXSBPBucjlL2uUSgPUu4H!UzEIQntGU2DeTGqecwk*XiJhLiic*RbrQliU9wQ!8J36Cc2grdSbeF9TeCHp!H6FC!qS40rekL31ZPFSunD8sJ*dQTOxPH9qC9ErHeoHvREFh0ypy4pa!!h5!15vvtwAPZgEcxcg2qSiA$$"
|
|
email := "frher9601@outlook.com"
|
|
|
|
fmt.Printf("=== Outlook REST API - No-Filter Strategy Test ===\n")
|
|
fmt.Printf("Account: %s\n\n", email)
|
|
|
|
// Step 1: Get access token
|
|
fmt.Println("[1] Exchanging refresh token...")
|
|
accessToken, err := exchangeToken(clientID, refreshToken)
|
|
if err != nil {
|
|
fmt.Printf(" FAILED: %v\n", err)
|
|
return
|
|
}
|
|
fmt.Printf(" OK: access_token (%d chars)\n\n", len(accessToken))
|
|
|
|
// Step 2: Fetch recent emails WITHOUT any filter (the fix)
|
|
fmt.Println("[2] Fetching recent 10 emails (no $filter)...")
|
|
reqURL := fmt.Sprintf("%s?$top=10&$orderby=ReceivedDateTime+desc&$select=Subject,BodyPreview,ReceivedDateTime,From",
|
|
outlookMailURL)
|
|
|
|
req, _ := http.NewRequest("GET", reqURL, nil)
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
client := &http.Client{Timeout: 15 * time.Second}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
fmt.Printf(" FAILED: %v\n", err)
|
|
return
|
|
}
|
|
body, _ := io.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
fmt.Printf(" FAILED (HTTP %d): %s\n", resp.StatusCode, string(body)[:min(len(body), 300)])
|
|
return
|
|
}
|
|
|
|
var result struct {
|
|
Value []struct {
|
|
Subject string `json:"Subject"`
|
|
BodyPreview string `json:"BodyPreview"`
|
|
ReceivedDateTime string `json:"ReceivedDateTime"`
|
|
From struct {
|
|
EmailAddress struct {
|
|
Address string `json:"Address"`
|
|
} `json:"EmailAddress"`
|
|
} `json:"From"`
|
|
} `json:"value"`
|
|
}
|
|
json.Unmarshal(body, &result)
|
|
fmt.Printf(" OK: %d emails returned\n\n", len(result.Value))
|
|
|
|
// Step 3: Client-side filter simulation
|
|
fmt.Println("[3] Client-side filtering (simulating fixed code)...")
|
|
notBefore := time.Now().Add(-48 * time.Hour) // last 48h
|
|
otpRegexp := regexp.MustCompile(`\b(\d{6})\b`)
|
|
|
|
foundOTP := ""
|
|
for i, e := range result.Value {
|
|
sender := strings.ToLower(e.From.EmailAddress.Address)
|
|
preview := e.BodyPreview
|
|
if len(preview) > 80 {
|
|
preview = preview[:80] + "..."
|
|
}
|
|
fmt.Printf(" [%d] from=%-45s subj=%q\n", i, sender, e.Subject)
|
|
|
|
// Filter: must be from OpenAI
|
|
if !strings.Contains(sender, "openai") {
|
|
fmt.Printf(" -> SKIP (not openai)\n")
|
|
continue
|
|
}
|
|
|
|
// Filter: time check
|
|
if e.ReceivedDateTime != "" {
|
|
if t, err := time.Parse("2006-01-02T15:04:05Z", e.ReceivedDateTime); err == nil {
|
|
if t.Before(notBefore) {
|
|
fmt.Printf(" -> SKIP (too old: %s)\n", e.ReceivedDateTime)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// Extract OTP
|
|
if m := otpRegexp.FindStringSubmatch(e.Subject); len(m) >= 2 {
|
|
foundOTP = m[1]
|
|
fmt.Printf(" -> OTP from subject: %s\n", foundOTP)
|
|
break
|
|
}
|
|
if m := otpRegexp.FindStringSubmatch(e.BodyPreview); len(m) >= 2 {
|
|
foundOTP = m[1]
|
|
fmt.Printf(" -> OTP from body: %s\n", foundOTP)
|
|
break
|
|
}
|
|
fmt.Printf(" -> OpenAI email but no OTP found\n")
|
|
}
|
|
|
|
fmt.Println()
|
|
if foundOTP != "" {
|
|
fmt.Printf("=== SUCCESS: OTP = %s ===\n", foundOTP)
|
|
} else {
|
|
fmt.Println("=== No OTP found (no recent OpenAI email in inbox) ===")
|
|
}
|
|
}
|
|
|
|
func exchangeToken(clientID, refreshToken string) (string, error) {
|
|
data := url.Values{
|
|
"client_id": {clientID},
|
|
"grant_type": {"refresh_token"},
|
|
"refresh_token": {refreshToken},
|
|
}
|
|
client := &http.Client{Timeout: 15 * time.Second}
|
|
resp, err := client.PostForm(msTokenURL, data)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer resp.Body.Close()
|
|
body, _ := io.ReadAll(resp.Body)
|
|
if resp.StatusCode != 200 {
|
|
cut := len(body)
|
|
if cut > 300 {
|
|
cut = 300
|
|
}
|
|
return "", fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body)[:cut])
|
|
}
|
|
var tokenResp struct {
|
|
AccessToken string `json:"access_token"`
|
|
}
|
|
json.Unmarshal(body, &tokenResp)
|
|
if tokenResp.AccessToken == "" {
|
|
return "", fmt.Errorf("no access_token in response")
|
|
}
|
|
return tokenResp.AccessToken, nil
|
|
}
|
|
|
|
func min(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|