github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/modules/access_key/access_key_models.go (about)

     1  package access_key
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/pkg/errors"
    11  
    12  	base "github.com/machinefi/w3bstream/pkg/depends/base/types"
    13  	"github.com/machinefi/w3bstream/pkg/depends/kit/sqlx/builder"
    14  	"github.com/machinefi/w3bstream/pkg/depends/kit/sqlx/datatypes"
    15  	"github.com/machinefi/w3bstream/pkg/depends/x/stringsx"
    16  	"github.com/machinefi/w3bstream/pkg/enums"
    17  	"github.com/machinefi/w3bstream/pkg/models"
    18  	"github.com/machinefi/w3bstream/pkg/types"
    19  )
    20  
    21  type CreateReqBase struct {
    22  	// Name access token name
    23  	Name string `json:"name"`
    24  	// ExpirationDays access token valid in ExpirationDays, if 0 means token will not be expired.
    25  	ExpirationDays int `json:"expirationDays,omitempty"`
    26  	// Description access token description
    27  	Desc string `json:"desc,omitempty"`
    28  	// Privileges operator group access privileges
    29  	Privileges GroupAccessPrivileges `json:"privileges,omitempty"`
    30  }
    31  
    32  type CreateAccountAccessKeyReq = CreateReqBase
    33  
    34  type CreateReq struct {
    35  	// IdentityID associated with a publisher, an account or other application
    36  	IdentityID types.SFID `json:"identityID,omitempty"`
    37  	// IdentityType associated type, default associated current account
    38  	IdentityType enums.AccessKeyIdentityType `json:"identityType,default='1'"`
    39  	CreateReqBase
    40  }
    41  
    42  type CreateRsp struct {
    43  	Name         string                      `json:"name"`
    44  	IdentityType enums.AccessKeyIdentityType `json:"identityType"`
    45  	IdentityID   types.SFID                  `json:"identityID"`
    46  	AccessKey    string                      `json:"accessKey"`
    47  	Privileges   []*GroupMetaWithPrivilege   `json:"privileges"`
    48  	ExpiredAt    *types.Timestamp            `json:"expiredAt,omitempty"`
    49  	Desc         string                      `json:"desc,omitempty"`
    50  }
    51  
    52  type UpdateReq struct {
    53  	ExpirationDays int                   `json:"expirationDays,omitempty"`
    54  	Desc           string                `json:"desc,omitempty"`
    55  	Privileges     GroupAccessPrivileges `json:"privileges,omitempty"`
    56  }
    57  
    58  type UpdateRsp struct {
    59  	Name         string                      `json:"name"`
    60  	IdentityType enums.AccessKeyIdentityType `json:"identityType"`
    61  	IdentityID   types.SFID                  `json:"identityID"`
    62  	Privileges   []*GroupMetaWithPrivilege   `json:"privileges"`
    63  	ExpiredAt    *types.Timestamp            `json:"expiredAt,omitempty"`
    64  	LastUsed     *types.Timestamp            `json:"lastUsed,omitempty"`
    65  	Desc         string                      `json:"desc,omitempty"`
    66  }
    67  
    68  func NewListDataByModel(v *models.AccessKey) *ListData {
    69  	ret := &ListData{
    70  		Name:           v.Name,
    71  		Desc:           v.Description,
    72  		OperationTimes: v.OperationTimes,
    73  	}
    74  	if !v.ExpiredAt.IsZero() {
    75  		ret.ExpiredAt = &base.Timestamp{Time: v.ExpiredAt.Time}
    76  	}
    77  	if !v.LastUsed.IsZero() {
    78  		ret.LastUsed = &base.Timestamp{Time: v.LastUsed.Time}
    79  	}
    80  	for name, perm := range v.Privileges {
    81  		ret.Privileges = append(ret.Privileges, GroupMetaWithPrivilege{
    82  			GroupMetaBase: GroupMetaBase{
    83  				Name: name,
    84  				Desc: gOperatorGroups[name].Desc,
    85  			},
    86  			Perm: perm,
    87  		})
    88  	}
    89  	return ret
    90  }
    91  
    92  type ListData struct {
    93  	Name       string                   `json:"name"`
    94  	ExpiredAt  *types.Timestamp         `json:"expiredAt,omitempty"`
    95  	LastUsed   *types.Timestamp         `json:"lastUsed,omitempty"`
    96  	Privileges []GroupMetaWithPrivilege `json:"privileges,omitempty"`
    97  	Desc       string                   `json:"desc,omitempty"`
    98  	datatypes.OperationTimes
    99  }
   100  
   101  type CondArgs struct {
   102  	AccountID      types.SFID                    `name:"-"`
   103  	Names          []string                      `in:"query" name:"name,omitempty"`
   104  	ExpiredAtBegin types.Timestamp               `in:"query" name:"expiredAtBegin,omitempty"`
   105  	ExpiredAtEnd   types.Timestamp               `in:"query" name:"expiredAtEnd,omitempty"`
   106  	IdentityIDs    types.SFIDs                   `in:"query" name:"identityID,omitempty"`
   107  	IdentityTypes  []enums.AccessKeyIdentityType `in:"query" name:"identityType,omitempty"`
   108  }
   109  
   110  func (r *CondArgs) Condition() builder.SqlCondition {
   111  	var (
   112  		m = &models.AccessKey{}
   113  		c []builder.SqlCondition
   114  	)
   115  	if r.AccountID != 0 {
   116  		c = append(c, m.ColAccountID().Eq(r.AccountID))
   117  	}
   118  	if len(r.Names) > 0 {
   119  		c = append(c, m.ColName().In(r.Names))
   120  	}
   121  	if !r.ExpiredAtEnd.IsZero() {
   122  		c = append(c, m.ColExpiredAt().Lte(r.ExpiredAtEnd))
   123  	}
   124  	if !r.ExpiredAtBegin.IsZero() {
   125  		c = append(c, m.ColExpiredAt().Gte(r.ExpiredAtBegin))
   126  	}
   127  	if len(r.IdentityIDs) > 0 {
   128  		c = append(c, m.ColIdentityID().In(r.IdentityIDs))
   129  	}
   130  	if len(r.IdentityTypes) > 0 {
   131  		c = append(c, m.ColIdentityType().In(r.IdentityTypes))
   132  	}
   133  	return builder.And(c...)
   134  }
   135  
   136  type ListReq struct {
   137  	CondArgs
   138  	datatypes.Pager
   139  }
   140  
   141  type ListRsp struct {
   142  	Data  []*ListData `json:"data"`
   143  	Total int64       `json:"total"`
   144  }
   145  
   146  var (
   147  	gAccessKeyVersion    = 1
   148  	gAccessKeyRandLength = 12
   149  	gBase64Encoding      = base64.RawURLEncoding
   150  )
   151  
   152  func NewAccessKeyContext(version int) *AccessKeyContext {
   153  	return &AccessKeyContext{
   154  		Version: version,
   155  		Rand:    stringsx.GenRandomVisibleString(gAccessKeyRandLength, '_'),
   156  		GenTS:   time.Now(),
   157  	}
   158  }
   159  
   160  func NewDefaultAccessKeyContext() *AccessKeyContext {
   161  	return NewAccessKeyContext(gAccessKeyVersion)
   162  }
   163  
   164  type AccessKeyContext struct {
   165  	// Version integer version fixed field
   166  	Version int
   167  	// GenTS access key generated timestamp (utc,seconds)
   168  	GenTS time.Time
   169  	// Rand random part, length: gAccessKeyRandLength
   170  	Rand string
   171  }
   172  
   173  func (c *AccessKeyContext) Regenerate() {
   174  	c.Rand = stringsx.GenRandomVisibleString(gAccessKeyRandLength, '_')
   175  }
   176  
   177  func (c AccessKeyContext) MarshalText() ([]byte, error) {
   178  	return []byte("w3b_" + gBase64Encoding.EncodeToString([]byte(
   179  		fmt.Sprintf("%d_%d_%s", c.Version, c.GenTS.UTC().Unix(), c.Rand),
   180  	))), nil
   181  }
   182  
   183  func (c *AccessKeyContext) UnmarshalText(data []byte) (err error) {
   184  	sep := []byte{'_'}
   185  
   186  	parts := bytes.SplitN(data, sep, 2)
   187  	if !bytes.Equal(parts[0], []byte("w3b")) {
   188  		return ErrInvalidPrefixOrPartCount
   189  	}
   190  	var raw []byte
   191  	raw, err = gBase64Encoding.DecodeString(string(parts[1]))
   192  	if err != nil {
   193  		err = errors.Wrap(ErrBase64DecodeFailed, err.Error())
   194  		return
   195  	}
   196  
   197  	contents := bytes.SplitN(raw, sep, 3)
   198  	if len(contents) != 3 {
   199  		return ErrInvalidContentsPartCount
   200  	}
   201  
   202  	c.Version, err = strconv.Atoi(string(contents[0]))
   203  	if err != nil {
   204  		return errors.Wrap(ErrParseVersionFailed, err.Error())
   205  	}
   206  	genTS, err := strconv.ParseInt(string(contents[1]), 10, 64)
   207  	if err != nil {
   208  		return errors.Wrap(ErrParseGenTsFailed, err.Error())
   209  	}
   210  	c.GenTS = time.Unix(genTS, 0)
   211  	switch c.Version {
   212  	case 1:
   213  		c.Rand = string(contents[2])
   214  		return
   215  	default:
   216  		return ErrInvalidVersion
   217  	}
   218  }
   219  
   220  func (c *AccessKeyContext) Equal(v *AccessKeyContext) bool {
   221  	return c.Version == v.Version &&
   222  		c.GenTS.UTC().Second() == v.GenTS.UTC().Second() &&
   223  		c.Rand == v.Rand
   224  }
   225  
   226  var (
   227  	ErrInvalidPrefixOrPartCount = errors.New("invalid prefix or part count")
   228  	ErrBase64DecodeFailed       = errors.New("base64 decode failed")
   229  	ErrInvalidContentsPartCount = errors.New("invalid part count of contents")
   230  	ErrParseVersionFailed       = errors.New("parse version failed")
   231  	ErrParseGenTsFailed         = errors.New("parse generate ts failed")
   232  	ErrInvalidVersion           = errors.New("invalid version")
   233  )