github.com/chainreactors/fingers@v1.2.1/fingers/nacos_fingerprint_test.go (about)

     1  package fingers
     2  
     3  import (
     4  	"crypto/tls"
     5  	"net/http"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/chainreactors/utils/encode"
    10  	"github.com/chainreactors/utils/httputils"
    11  	"gopkg.in/yaml.v3"
    12  )
    13  
    14  func TestNacosFingerprint_RealSite(t *testing.T) {
    15  	if testing.Short() {
    16  		t.Skip("skipping live network test in short mode")
    17  	}
    18  	const (
    19  		baseURL         = "https://nacos.lzfzkj.com"
    20  		fingerSendPath  = "/nacos/"
    21  		faviconSendPath = "/nacos/console-ui/public/img/nacos-logo.png"
    22  		expectedMMH3    = "13942501"
    23  	)
    24  
    25  	finger := &Finger{
    26  		Name:              "nacos",
    27  		Focus:             true,
    28  		Tags:              []string{"nacos"},
    29  		Protocol:          HTTPProtocol,
    30  		DefaultPort:       []string{"80"},
    31  		SendDataStr:       fingerSendPath,
    32  		EnableMatchDetail: true,
    33  		Rules: Rules{
    34  			{
    35  				Regexps: &Regexps{
    36  					Body: []string{"<title>Nacos</title>"},
    37  				},
    38  			},
    39  			{
    40  				Favicon: &Favicons{
    41  					Mmh3: []string{expectedMMH3},
    42  				},
    43  				SendDataStr: faviconSendPath,
    44  				Level:       2,
    45  			},
    46  		},
    47  	}
    48  
    49  	if err := finger.Compile(false); err != nil {
    50  		t.Fatalf("failed to compile finger: %v", err)
    51  	}
    52  
    53  	client := &http.Client{
    54  		Timeout: 20 * time.Second,
    55  		Transport: &http.Transport{
    56  			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    57  		},
    58  	}
    59  
    60  	sent := make([]string, 0, 4)
    61  	sender := Sender(func(data []byte) ([]byte, bool) {
    62  		path := string(data)
    63  		sent = append(sent, path)
    64  		req, err := http.NewRequest(http.MethodGet, baseURL+path, nil)
    65  		if err != nil {
    66  			t.Logf("request build error for %s: %v", path, err)
    67  			return nil, false
    68  		}
    69  		req.Header.Set("User-Agent", "fingers-test/nacos-fingerprint")
    70  		resp, err := client.Do(req)
    71  		if err != nil {
    72  			t.Logf("request error for %s: %v", path, err)
    73  			return nil, false
    74  		}
    75  		defer resp.Body.Close()
    76  		return httputils.ReadRaw(resp), true
    77  	})
    78  
    79  	frame, _, ok := finger.ActiveMatch(2, sender)
    80  	if !ok || frame == nil {
    81  		t.Fatalf("expected nacos active match to succeed")
    82  	}
    83  
    84  	// Validate the favicon hash from the real site.
    85  	req, err := http.NewRequest(http.MethodGet, baseURL+faviconSendPath, nil)
    86  	if err != nil {
    87  		t.Fatalf("failed to build favicon request: %v", err)
    88  	}
    89  	resp, err := client.Do(req)
    90  	if err != nil {
    91  		t.Skipf("network error fetching favicon path: %v", err)
    92  		return
    93  	}
    94  	defer resp.Body.Close()
    95  	raw := httputils.ReadRaw(resp)
    96  	body, _, splitOK := httputils.SplitHttpRaw(raw)
    97  	if !splitOK || len(body) == 0 {
    98  		t.Fatalf("failed to split favicon response body")
    99  	}
   100  	if got := encode.Mmh3Hash32(body); got != expectedMMH3 {
   101  		t.Fatalf("unexpected mmh3 for favicon: got %s want %s", got, expectedMMH3)
   102  	}
   103  
   104  	t.Logf("sent paths: %v", sent)
   105  	if frame.MatchDetail != nil {
   106  		t.Logf("matcher detail: %+v", *frame.MatchDetail)
   107  	}
   108  }
   109  
   110  func TestNacosFingerprint_RealSite_RuleSendDataOnly(t *testing.T) {
   111  	if testing.Short() {
   112  		t.Skip("skipping live network test in short mode")
   113  	}
   114  	const (
   115  		baseURL         = "https://nacos.lzfzkj.com"
   116  		faviconSendPath = "/nacos/console-ui/public/img/nacos-logo.png"
   117  		expectedMMH3    = "13942501"
   118  	)
   119  
   120  	yamlContent := `name: nacos
   121  focus: true
   122  tag:
   123  - nacos
   124  rule:
   125  - regexps:
   126      body:
   127      - <title>Nacos</title>
   128  - favicon:
   129      mmh3:
   130        - "` + expectedMMH3 + `"
   131    send_data: ` + faviconSendPath + `
   132  `
   133  
   134  	var parsed Fingers
   135  	if err := yaml.Unmarshal([]byte(yamlContent), &parsed); err != nil {
   136  		var single Finger
   137  		if errSingle := yaml.Unmarshal([]byte(yamlContent), &single); errSingle != nil {
   138  			t.Fatalf("failed to parse yaml: %v", err)
   139  		}
   140  		parsed = Fingers{&single}
   141  	}
   142  	if len(parsed) == 0 || parsed[0] == nil {
   143  		t.Fatalf("no fingerprint parsed from yaml")
   144  	}
   145  	finger := parsed[0]
   146  	finger.EnableMatchDetail = true
   147  	if err := finger.Compile(false); err != nil {
   148  		t.Fatalf("failed to compile finger: %v", err)
   149  	}
   150  
   151  	client := &http.Client{
   152  		Timeout: 20 * time.Second,
   153  		Transport: &http.Transport{
   154  			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
   155  		},
   156  	}
   157  
   158  	sent := make([]string, 0, 4)
   159  	sender := Sender(func(data []byte) ([]byte, bool) {
   160  		path := string(data)
   161  		sent = append(sent, path)
   162  		req, err := http.NewRequest(http.MethodGet, baseURL+path, nil)
   163  		if err != nil {
   164  			t.Logf("request build error for %s: %v", path, err)
   165  			return nil, false
   166  		}
   167  		req.Header.Set("User-Agent", "fingers-test/nacos-fingerprint")
   168  		resp, err := client.Do(req)
   169  		if err != nil {
   170  			t.Logf("request error for %s: %v", path, err)
   171  			return nil, false
   172  		}
   173  		defer resp.Body.Close()
   174  		return httputils.ReadRaw(resp), true
   175  	})
   176  
   177  	frame, _, ok := finger.ActiveMatch(2, sender)
   178  	if !ok || frame == nil {
   179  		t.Fatalf("expected nacos active match to succeed")
   180  	}
   181  
   182  	if len(sent) == 0 {
   183  		t.Fatalf("expected at least one send_data to be sent")
   184  	}
   185  
   186  	t.Logf("sent paths: %v", sent)
   187  	if frame.MatchDetail != nil {
   188  		t.Logf("matcher detail: %+v", *frame.MatchDetail)
   189  	}
   190  }