github.com/iDigitalFlame/xmt@v0.5.4/com/wc2/target.go (about)

     1  // Copyright (C) 2020 - 2023 iDigitalFlame
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  //
    16  
    17  package wc2
    18  
    19  import (
    20  	"net/http"
    21  
    22  	"github.com/iDigitalFlame/xmt/util/text"
    23  )
    24  
    25  // TargetEmpty is a Target that does not have anything set and will not mutate a
    26  // Request.
    27  var TargetEmpty Target
    28  
    29  // Target is a struct that is composed of three separate Stringer interfaces.
    30  // These are called via their 'String' function to specify the User-Agent, URL
    31  // and Host string values. They can be set to static strings using the
    32  // 'text.String' wrapper. This struct can be used as a C2 client connector. If
    33  // the Client property is not set, the DefaultClient value will be used.
    34  type Target struct {
    35  	URL, Host, Agent Stringer
    36  	Headers          map[string]Stringer
    37  }
    38  
    39  // Stringer is a utility interface that takes a single 'String() string'
    40  // function for returning a string to be used as a Target.
    41  type Stringer interface {
    42  	String() string
    43  }
    44  
    45  // Reset sets all the Target values to nil. This allows for an empty Target to
    46  // be used.
    47  func (t *Target) Reset() {
    48  	if t.URL, t.Host, t.Agent = nil, nil, nil; t.Headers != nil && len(t.Headers) > 0 {
    49  		for k := range t.Headers {
    50  			delete(t.Headers, k)
    51  		}
    52  	}
    53  }
    54  
    55  // Rule will attempt to generate a Rule that matches this generator using the
    56  // current configuration.
    57  //
    58  // Rules will only be added if the settings implement the 'MatchString(string) bool'
    59  // function. Otherwise, the specified rule will attempt to match using a Text
    60  // Matcher.
    61  //
    62  // Empty Target return an empty rule.
    63  func (t Target) Rule() Rule {
    64  	var r Rule
    65  	if t.empty() {
    66  		return r
    67  	}
    68  	if t.URL != nil {
    69  		if m, ok := t.URL.(Matcher); ok {
    70  			r.URL = m
    71  		} else if m, ok := t.URL.(text.Matcher); ok {
    72  			r.URL = m.Match()
    73  		} else {
    74  			r.URL = text.Matcher(t.URL.String()).Match()
    75  		}
    76  	}
    77  	if t.Host != nil {
    78  		if m, ok := t.Host.(Matcher); ok {
    79  			r.Host = m
    80  		} else if m, ok := t.Host.(text.Matcher); ok {
    81  			r.Host = m.Match()
    82  		} else {
    83  			r.Host = text.Matcher(t.Host.String()).Match()
    84  		}
    85  	}
    86  	if t.Agent != nil {
    87  		if m, ok := t.Agent.(Matcher); ok {
    88  			r.Agent = m
    89  		} else if m, ok := t.Agent.(text.Matcher); ok {
    90  			r.Agent = m.Match()
    91  		} else {
    92  			r.Agent = text.Matcher(t.Agent.String()).Match()
    93  		}
    94  	}
    95  	if t.Headers != nil && len(t.Headers) > 0 {
    96  		r.Headers = make(map[string]Matcher, len(t.Headers))
    97  		for k, v := range t.Headers {
    98  			if m, ok := v.(Matcher); ok {
    99  				r.Headers[k] = m
   100  			} else if m, ok := v.(text.Matcher); ok {
   101  				r.Headers[k] = m.Match()
   102  			} else {
   103  				r.Headers[k] = text.Matcher(v.String()).Match()
   104  			}
   105  		}
   106  	}
   107  	return r
   108  }
   109  func (t Target) empty() bool {
   110  	return t.Agent == nil && t.Host == nil && t.URL == nil && len(t.Headers) == 0
   111  }
   112  func (t *Target) mutate(r *http.Request) {
   113  	if t.URL != nil {
   114  		s := t.URL.String()
   115  		if len(s) > 0 && s[0] != '/' {
   116  			r.URL.Path = "/" + s
   117  		} else {
   118  			r.URL.Path = s
   119  		}
   120  	}
   121  	if t.Host != nil {
   122  		r.Host = t.Host.String()
   123  	}
   124  	if t.Agent != nil {
   125  		r.Header.Set(userAgent, t.Agent.String())
   126  	}
   127  	for k, v := range t.Headers {
   128  		r.Header.Set(k, v.String())
   129  	}
   130  }
   131  
   132  // Header adds the stringer to the Target's header set.
   133  //
   134  // This function will create the headers map if it's nil.
   135  func (t *Target) Header(k string, v Stringer) {
   136  	if t.Headers == nil {
   137  		t.Headers = make(map[string]Stringer)
   138  	}
   139  	t.Headers[k] = v
   140  }