github.com/LagrangeDev/LagrangeGo@v0.0.0-20240512064304-ad4a85e10cb4/client/sign/http.go (about)

     1  package sign
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"net/http"
     9  	"net/url"
    10  	"strconv"
    11  	"time"
    12  
    13  	"github.com/LagrangeDev/LagrangeGo/client/http2"
    14  )
    15  
    16  var (
    17  	signMap = map[string]struct{}{} // 只在启动时初始化, 无并发问题
    18  )
    19  
    20  func init() {
    21  	signPkgList := []string{
    22  		"trpc.o3.ecdh_access.EcdhAccess.SsoEstablishShareKey",
    23  		"trpc.o3.ecdh_access.EcdhAccess.SsoSecureAccess",
    24  		"trpc.o3.report.Report.SsoReport",
    25  		"MessageSvc.PbSendMsg",
    26  		// "wtlogin.trans_emp",
    27  		"wtlogin.login",
    28  		// "trpc.login.ecdh.EcdhService.SsoKeyExchange",
    29  		"trpc.login.ecdh.EcdhService.SsoNTLoginPasswordLogin",
    30  		"trpc.login.ecdh.EcdhService.SsoNTLoginEasyLogin",
    31  		"trpc.login.ecdh.EcdhService.SsoNTLoginPasswordLoginNewDevice",
    32  		"trpc.login.ecdh.EcdhService.SsoNTLoginEasyLoginUnusualDevice",
    33  		"trpc.login.ecdh.EcdhService.SsoNTLoginPasswordLoginUnusualDevice",
    34  		"OidbSvcTrpcTcp.0x11ec_1",
    35  		"OidbSvcTrpcTcp.0x758_1",
    36  		"OidbSvcTrpcTcp.0x7c2_5",
    37  		"OidbSvcTrpcTcp.0x10db_1",
    38  		"OidbSvcTrpcTcp.0x8a1_7",
    39  		"OidbSvcTrpcTcp.0x89a_0",
    40  		"OidbSvcTrpcTcp.0x89a_15",
    41  		"OidbSvcTrpcTcp.0x88d_0",
    42  		"OidbSvcTrpcTcp.0x88d_14",
    43  		"OidbSvcTrpcTcp.0x112a_1",
    44  		"OidbSvcTrpcTcp.0x587_74",
    45  		"OidbSvcTrpcTcp.0x1100_1",
    46  		"OidbSvcTrpcTcp.0x1102_1",
    47  		"OidbSvcTrpcTcp.0x1103_1",
    48  		"OidbSvcTrpcTcp.0x1107_1",
    49  		"OidbSvcTrpcTcp.0x1105_1",
    50  		"OidbSvcTrpcTcp.0xf88_1",
    51  		"OidbSvcTrpcTcp.0xf89_1",
    52  		"OidbSvcTrpcTcp.0xf57_1",
    53  		"OidbSvcTrpcTcp.0xf57_106",
    54  		"OidbSvcTrpcTcp.0xf57_9",
    55  		"OidbSvcTrpcTcp.0xf55_1",
    56  		"OidbSvcTrpcTcp.0xf67_1",
    57  		"OidbSvcTrpcTcp.0xf67_5",
    58  	}
    59  
    60  	for _, cmd := range signPkgList {
    61  		signMap[cmd] = struct{}{}
    62  	}
    63  }
    64  
    65  func containSignPKG(cmd string) bool {
    66  	_, ok := signMap[cmd]
    67  	return ok
    68  }
    69  
    70  func NewProviderURL(rawUrl string, log func(msg string)) func(string, uint32, []byte) map[string]string {
    71  	if rawUrl == "" {
    72  		return nil
    73  	}
    74  	return func(cmd string, seq uint32, buf []byte) map[string]string {
    75  		if !containSignPKG(cmd) {
    76  			return nil
    77  		}
    78  		startTime := time.Now().UnixMilli()
    79  		resp := signResponse{}
    80  		err := httpGet(rawUrl, map[string]string{
    81  			"cmd": cmd,
    82  			"seq": strconv.Itoa(int(seq)),
    83  			"src": fmt.Sprintf("%x", buf),
    84  		}, 8*time.Second, &resp)
    85  		if err != nil {
    86  			log(err.Error())
    87  			return nil
    88  		}
    89  
    90  		log(fmt.Sprintf("signed for [%s:%d](%dms)",
    91  			cmd, seq, time.Now().UnixMilli()-startTime))
    92  
    93  		return map[string]string{
    94  			"sign":  resp.Value.Sign,
    95  			"extra": resp.Value.Extra,
    96  			"token": resp.Value.Token,
    97  		}
    98  	}
    99  }
   100  
   101  func httpGet(rawUrl string, queryParams map[string]string, timeout time.Duration, target interface{}) error {
   102  	u, err := url.Parse(rawUrl)
   103  	if err != nil {
   104  		return fmt.Errorf("failed to parse URL: %w", err)
   105  	}
   106  
   107  	q := u.Query()
   108  	for k, v := range queryParams {
   109  		q.Set(k, v)
   110  	}
   111  	u.RawQuery = q.Encode()
   112  
   113  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
   114  	defer cancel()
   115  
   116  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
   117  	if err != nil {
   118  		return fmt.Errorf("failed to create GET request: %w", err)
   119  	}
   120  
   121  	resp, err := http2.TRSClient.Do(req)
   122  	if err != nil {
   123  		if errors.Is(ctx.Err(), context.DeadlineExceeded) {
   124  			return fmt.Errorf("request timed out")
   125  		}
   126  		resp, err = http2.DefaultClient.Do(req)
   127  		if err != nil {
   128  			if errors.Is(ctx.Err(), context.DeadlineExceeded) {
   129  				return fmt.Errorf("request timed out")
   130  			}
   131  			return fmt.Errorf("failed to perform GET request: %w", err)
   132  		}
   133  	}
   134  	defer resp.Body.Close()
   135  
   136  	if resp.StatusCode != http.StatusOK {
   137  		return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
   138  	}
   139  
   140  	if err := json.NewDecoder(resp.Body).Decode(target); err != nil {
   141  		return fmt.Errorf("failed to unmarshal JSON response: %w", err)
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  type signResponse struct {
   148  	Value struct {
   149  		Sign  string `json:"sign"`
   150  		Extra string `json:"extra"`
   151  		Token string `json:"token"`
   152  	} `json:"value"`
   153  }