github.com/nats-io/jwt/v2@v2.5.6/v1compat/types.go (about)

     1  /*
     2   * Copyright 2018-2019 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package jwt
    17  
    18  import (
    19  	"encoding/json"
    20  	"fmt"
    21  	"net"
    22  	"strings"
    23  	"time"
    24  )
    25  
    26  // ExportType defines the type of import/export.
    27  type ExportType int
    28  
    29  const (
    30  	// Unknown is used if we don't know the type
    31  	Unknown ExportType = iota
    32  	// Stream defines the type field value for a stream "stream"
    33  	Stream
    34  	// Service defines the type field value for a service "service"
    35  	Service
    36  )
    37  
    38  func (t ExportType) String() string {
    39  	switch t {
    40  	case Stream:
    41  		return "stream"
    42  	case Service:
    43  		return "service"
    44  	}
    45  	return "unknown"
    46  }
    47  
    48  // MarshalJSON marshals the enum as a quoted json string
    49  func (t *ExportType) MarshalJSON() ([]byte, error) {
    50  	switch *t {
    51  	case Stream:
    52  		return []byte("\"stream\""), nil
    53  	case Service:
    54  		return []byte("\"service\""), nil
    55  	}
    56  	return nil, fmt.Errorf("unknown export type")
    57  }
    58  
    59  // UnmarshalJSON unmashals a quoted json string to the enum value
    60  func (t *ExportType) UnmarshalJSON(b []byte) error {
    61  	var j string
    62  	err := json.Unmarshal(b, &j)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	switch j {
    67  	case "stream":
    68  		*t = Stream
    69  		return nil
    70  	case "service":
    71  		*t = Service
    72  		return nil
    73  	}
    74  	return fmt.Errorf("unknown export type")
    75  }
    76  
    77  // Subject is a string that represents a NATS subject
    78  type Subject string
    79  
    80  // Validate checks that a subject string is valid, ie not empty and without spaces
    81  func (s Subject) Validate(vr *ValidationResults) {
    82  	v := string(s)
    83  	if v == "" {
    84  		vr.AddError("subject cannot be empty")
    85  	}
    86  	if strings.Contains(v, " ") {
    87  		vr.AddError("subject %q cannot have spaces", v)
    88  	}
    89  }
    90  
    91  // HasWildCards is used to check if a subject contains a > or *
    92  func (s Subject) HasWildCards() bool {
    93  	v := string(s)
    94  	return strings.HasSuffix(v, ".>") ||
    95  		strings.Contains(v, ".*.") ||
    96  		strings.HasSuffix(v, ".*") ||
    97  		strings.HasPrefix(v, "*.") ||
    98  		v == "*" ||
    99  		v == ">"
   100  }
   101  
   102  // IsContainedIn does a simple test to see if the subject is contained in another subject
   103  func (s Subject) IsContainedIn(other Subject) bool {
   104  	otherArray := strings.Split(string(other), ".")
   105  	myArray := strings.Split(string(s), ".")
   106  
   107  	if len(myArray) > len(otherArray) && otherArray[len(otherArray)-1] != ">" {
   108  		return false
   109  	}
   110  
   111  	if len(myArray) < len(otherArray) {
   112  		return false
   113  	}
   114  
   115  	for ind, tok := range otherArray {
   116  		myTok := myArray[ind]
   117  
   118  		if ind == len(otherArray)-1 && tok == ">" {
   119  			return true
   120  		}
   121  
   122  		if tok != myTok && tok != "*" {
   123  			return false
   124  		}
   125  	}
   126  
   127  	return true
   128  }
   129  
   130  // NamedSubject is the combination of a subject and a name for it
   131  type NamedSubject struct {
   132  	Name    string  `json:"name,omitempty"`
   133  	Subject Subject `json:"subject,omitempty"`
   134  }
   135  
   136  // Validate checks the subject
   137  func (ns *NamedSubject) Validate(vr *ValidationResults) {
   138  	ns.Subject.Validate(vr)
   139  }
   140  
   141  // TimeRange is used to represent a start and end time
   142  type TimeRange struct {
   143  	Start string `json:"start,omitempty"`
   144  	End   string `json:"end,omitempty"`
   145  }
   146  
   147  // Validate checks the values in a time range struct
   148  func (tr *TimeRange) Validate(vr *ValidationResults) {
   149  	format := "15:04:05"
   150  
   151  	if tr.Start == "" {
   152  		vr.AddError("time ranges start must contain a start")
   153  	} else {
   154  		_, err := time.Parse(format, tr.Start)
   155  		if err != nil {
   156  			vr.AddError("start in time range is invalid %q", tr.Start)
   157  		}
   158  	}
   159  
   160  	if tr.End == "" {
   161  		vr.AddError("time ranges end must contain an end")
   162  	} else {
   163  		_, err := time.Parse(format, tr.End)
   164  		if err != nil {
   165  			vr.AddError("end in time range is invalid %q", tr.End)
   166  		}
   167  	}
   168  }
   169  
   170  // Limits are used to control acccess for users and importing accounts
   171  // Src is a comma separated list of CIDR specifications
   172  type Limits struct {
   173  	Max     int64       `json:"max,omitempty"`
   174  	Payload int64       `json:"payload,omitempty"`
   175  	Src     string      `json:"src,omitempty"`
   176  	Times   []TimeRange `json:"times,omitempty"`
   177  }
   178  
   179  // Validate checks the values in a limit struct
   180  func (l *Limits) Validate(vr *ValidationResults) {
   181  	if l.Max < 0 {
   182  		vr.AddError("limits cannot contain a negative maximum, %d", l.Max)
   183  	}
   184  	if l.Payload < 0 {
   185  		vr.AddError("limits cannot contain a negative payload, %d", l.Payload)
   186  	}
   187  
   188  	if l.Src != "" {
   189  		elements := strings.Split(l.Src, ",")
   190  
   191  		for _, cidr := range elements {
   192  			cidr = strings.TrimSpace(cidr)
   193  			_, ipNet, err := net.ParseCIDR(cidr)
   194  			if err != nil || ipNet == nil {
   195  				vr.AddError("invalid cidr %q in user src limits", cidr)
   196  			}
   197  		}
   198  	}
   199  
   200  	if l.Times != nil && len(l.Times) > 0 {
   201  		for _, t := range l.Times {
   202  			t.Validate(vr)
   203  		}
   204  	}
   205  }
   206  
   207  // Permission defines allow/deny subjects
   208  type Permission struct {
   209  	Allow StringList `json:"allow,omitempty"`
   210  	Deny  StringList `json:"deny,omitempty"`
   211  }
   212  
   213  // Validate the allow, deny elements of a permission
   214  func (p *Permission) Validate(vr *ValidationResults) {
   215  	for _, subj := range p.Allow {
   216  		Subject(subj).Validate(vr)
   217  	}
   218  	for _, subj := range p.Deny {
   219  		Subject(subj).Validate(vr)
   220  	}
   221  }
   222  
   223  // ResponsePermission can be used to allow responses to any reply subject
   224  // that is received on a valid subscription.
   225  type ResponsePermission struct {
   226  	MaxMsgs int           `json:"max"`
   227  	Expires time.Duration `json:"ttl"`
   228  }
   229  
   230  // Validate the response permission.
   231  func (p *ResponsePermission) Validate(vr *ValidationResults) {
   232  	// Any values can be valid for now.
   233  }
   234  
   235  // Permissions are used to restrict subject access, either on a user or for everyone on a server by default
   236  type Permissions struct {
   237  	Pub  Permission          `json:"pub,omitempty"`
   238  	Sub  Permission          `json:"sub,omitempty"`
   239  	Resp *ResponsePermission `json:"resp,omitempty"`
   240  }
   241  
   242  // Validate the pub and sub fields in the permissions list
   243  func (p *Permissions) Validate(vr *ValidationResults) {
   244  	p.Pub.Validate(vr)
   245  	p.Sub.Validate(vr)
   246  	if p.Resp != nil {
   247  		p.Resp.Validate(vr)
   248  	}
   249  }
   250  
   251  // StringList is a wrapper for an array of strings
   252  type StringList []string
   253  
   254  // Contains returns true if the list contains the string
   255  func (u *StringList) Contains(p string) bool {
   256  	for _, t := range *u {
   257  		if t == p {
   258  			return true
   259  		}
   260  	}
   261  	return false
   262  }
   263  
   264  // Add appends 1 or more strings to a list
   265  func (u *StringList) Add(p ...string) {
   266  	for _, v := range p {
   267  		if !u.Contains(v) && v != "" {
   268  			*u = append(*u, v)
   269  		}
   270  	}
   271  }
   272  
   273  // Remove removes 1 or more strings from a list
   274  func (u *StringList) Remove(p ...string) {
   275  	for _, v := range p {
   276  		for i, t := range *u {
   277  			if t == v {
   278  				a := *u
   279  				*u = append(a[:i], a[i+1:]...)
   280  				break
   281  			}
   282  		}
   283  	}
   284  }
   285  
   286  // TagList is a unique array of lower case strings
   287  // All tag list methods lower case the strings in the arguments
   288  type TagList []string
   289  
   290  // Contains returns true if the list contains the tags
   291  func (u *TagList) Contains(p string) bool {
   292  	p = strings.ToLower(p)
   293  	for _, t := range *u {
   294  		if t == p {
   295  			return true
   296  		}
   297  	}
   298  	return false
   299  }
   300  
   301  // Add appends 1 or more tags to a list
   302  func (u *TagList) Add(p ...string) {
   303  	for _, v := range p {
   304  		v = strings.ToLower(v)
   305  		if !u.Contains(v) && v != "" {
   306  			*u = append(*u, v)
   307  		}
   308  	}
   309  }
   310  
   311  // Remove removes 1 or more tags from a list
   312  func (u *TagList) Remove(p ...string) {
   313  	for _, v := range p {
   314  		v = strings.ToLower(v)
   315  		for i, t := range *u {
   316  			if t == v {
   317  				a := *u
   318  				*u = append(a[:i], a[i+1:]...)
   319  				break
   320  			}
   321  		}
   322  	}
   323  }
   324  
   325  // Identity is used to associate an account or operator with a real entity
   326  type Identity struct {
   327  	ID    string `json:"id,omitempty"`
   328  	Proof string `json:"proof,omitempty"`
   329  }
   330  
   331  // Validate checks the values in an Identity
   332  func (u *Identity) Validate(vr *ValidationResults) {
   333  	//Fixme identity validation
   334  }