github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/cmd/srv-applet-mgr/apis/middleware/current_user.go (about)

     1  package middleware
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  
     7  	"github.com/machinefi/w3bstream/pkg/depends/kit/httptransport/httpx"
     8  	"github.com/machinefi/w3bstream/pkg/depends/kit/logr"
     9  	"github.com/machinefi/w3bstream/pkg/depends/kit/statusx"
    10  	"github.com/machinefi/w3bstream/pkg/depends/x/misc/must"
    11  	"github.com/machinefi/w3bstream/pkg/enums"
    12  	"github.com/machinefi/w3bstream/pkg/errors/status"
    13  	"github.com/machinefi/w3bstream/pkg/models"
    14  	"github.com/machinefi/w3bstream/pkg/modules/account"
    15  	"github.com/machinefi/w3bstream/pkg/modules/applet"
    16  	"github.com/machinefi/w3bstream/pkg/modules/blockchain"
    17  	"github.com/machinefi/w3bstream/pkg/modules/cronjob"
    18  	"github.com/machinefi/w3bstream/pkg/modules/deploy"
    19  	"github.com/machinefi/w3bstream/pkg/modules/operator"
    20  	"github.com/machinefi/w3bstream/pkg/modules/project"
    21  	"github.com/machinefi/w3bstream/pkg/modules/publisher"
    22  	"github.com/machinefi/w3bstream/pkg/modules/resource"
    23  	"github.com/machinefi/w3bstream/pkg/modules/strategy"
    24  	"github.com/machinefi/w3bstream/pkg/modules/trafficlimit"
    25  	"github.com/machinefi/w3bstream/pkg/types"
    26  )
    27  
    28  type ContextAccountAuth struct {
    29  	httpx.MethodGet
    30  }
    31  
    32  var contextAccountAuthKey = reflect.TypeOf(ContextAccountAuth{}).String()
    33  
    34  func (r *ContextAccountAuth) ContextKey() string { return contextAccountAuthKey }
    35  
    36  func (r *ContextAccountAuth) Output(ctx context.Context) (interface{}, error) {
    37  	ctx, l := logr.Start(ctx, "api.mw.ContextAccountAuth")
    38  	defer l.End()
    39  
    40  	pl, err := ParseJwtAuthContentFromContext(ctx)
    41  	if err != nil {
    42  		return nil, status.InvalidAuthAccountID.StatusErr().WithDesc(err.Error())
    43  	}
    44  
    45  	switch pl.IdentityType {
    46  	// must unknown or account
    47  	case enums.ACCESS_KEY_IDENTITY_TYPE__ACCOUNT, enums.ACCESS_KEY_IDENTITY_TYPE_UNKNOWN:
    48  		ca, err := account.GetAccountByAccountID(ctx, pl.IdentityID)
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  		return &CurrentAccount{*ca}, nil
    53  	default:
    54  		return nil, status.InvalidAuthValue
    55  	}
    56  }
    57  
    58  func MustCurrentAccountFromContext(ctx context.Context) *CurrentAccount {
    59  	ca, ok := ctx.Value(contextAccountAuthKey).(*CurrentAccount)
    60  	must.BeTrue(ok)
    61  	return ca
    62  }
    63  
    64  func CurrentAccountFromContext(ctx context.Context) (*CurrentAccount, bool) {
    65  	ca, ok := ctx.Value(contextAccountAuthKey).(*CurrentAccount)
    66  	return ca, ok
    67  }
    68  
    69  type CurrentAccount struct {
    70  	models.Account
    71  }
    72  
    73  func (v *CurrentAccount) CheckRole(role enums.AccountRole) (*CurrentAccount, bool) {
    74  	if v.Role == role {
    75  		return v, true
    76  	}
    77  	return nil, false
    78  }
    79  
    80  func (v *CurrentAccount) WithAccount(ctx context.Context) context.Context {
    81  	return types.WithAccount(ctx, &v.Account)
    82  }
    83  
    84  // WithProjectContextByName With project context by project name(in database)
    85  func (v *CurrentAccount) WithProjectContextByName(ctx context.Context, name string) (context.Context, error) {
    86  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithProjectContextByName")
    87  	defer l.End()
    88  
    89  	prj, err := project.GetByName(ctx, name)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	if v.Role == enums.ACCOUNT_ROLE__ADMIN || v.AccountID == prj.AccountID {
    94  		return types.WithProject(ctx, prj), nil
    95  	}
    96  
    97  	return nil, status.NoProjectPermission
    98  }
    99  
   100  // WithProjectContextBySFID With project context by project SFID
   101  func (v *CurrentAccount) WithProjectContextBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   102  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithProjectContextBySFID")
   103  	defer l.End()
   104  
   105  	prj, err := project.GetBySFID(ctx, id)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	if v.Role == enums.ACCOUNT_ROLE__ADMIN || v.AccountID == prj.AccountID {
   110  		return types.WithProject(ctx, prj), nil
   111  	}
   112  
   113  	return nil, status.NoProjectPermission
   114  }
   115  
   116  // WithAppletContextBySFID With applet contexts by applet SFID
   117  func (v *CurrentAccount) WithAppletContextBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   118  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithAppletContextBySFID")
   119  	defer l.End()
   120  
   121  	app, err := applet.GetBySFID(ctx, id)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  	ctx = types.WithApplet(ctx, app)
   126  
   127  	ctx, err = v.WithProjectContextBySFID(ctx, app.ProjectID)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	ins, err := deploy.GetByAppletSFID(ctx, app.AppletID)
   133  	if err != nil {
   134  		se, ok := statusx.IsStatusErr(err)
   135  		if !ok || !se.Is(status.InstanceNotFound) {
   136  			return nil, err
   137  		}
   138  	} else {
   139  		ctx = types.WithInstance(ctx, ins)
   140  	}
   141  
   142  	return ctx, nil
   143  }
   144  
   145  func (v *CurrentAccount) WithResourceContextBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   146  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithResourceContextBySFID")
   147  	defer l.End()
   148  
   149  	res, err := resource.GetBySFID(ctx, id)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	return types.WithResource(ctx, res), nil
   155  }
   156  
   157  // WithInstanceContextBySFID With full contexts by instance SFID
   158  func (v *CurrentAccount) WithInstanceContextBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   159  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithInstanceContextBySFID")
   160  	defer l.End()
   161  
   162  	var (
   163  		ins *models.Instance
   164  		app *models.Applet
   165  		res *models.Resource
   166  		err error
   167  	)
   168  	if ins, err = deploy.GetBySFID(ctx, id); err != nil {
   169  		return nil, err
   170  	}
   171  	ctx = types.WithInstance(ctx, ins)
   172  
   173  	if app, err = applet.GetBySFID(ctx, ins.AppletID); err != nil {
   174  		return nil, err
   175  	}
   176  	ctx = types.WithApplet(ctx, app)
   177  
   178  	if ctx, err = v.WithProjectContextBySFID(ctx, app.ProjectID); err != nil {
   179  		return nil, err
   180  	}
   181  
   182  	if res, err = resource.GetBySFID(ctx, app.ResourceID); err != nil {
   183  		return nil, err
   184  	}
   185  	return types.WithResource(ctx, res), nil
   186  }
   187  
   188  func (v *CurrentAccount) WithStrategyBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   189  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithStrategyBySFID")
   190  	defer l.End()
   191  
   192  	sty, err := strategy.GetBySFID(ctx, id)
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  	ctx = types.WithStrategy(ctx, sty)
   197  	return v.WithProjectContextBySFID(ctx, sty.ProjectID)
   198  }
   199  
   200  func (v *CurrentAccount) WithPublisherBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   201  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithPublisherBySFID")
   202  	defer l.End()
   203  
   204  	pub, err := publisher.GetBySFID(ctx, id)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	ctx = types.WithPublisher(ctx, pub)
   209  	return v.WithProjectContextBySFID(ctx, pub.ProjectID)
   210  }
   211  
   212  func (v *CurrentAccount) WithResourceOwnerContextBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   213  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithResourceOwnerContextBySFID")
   214  	defer l.End()
   215  
   216  	ship, err := resource.GetOwnerByAccountAndSFID(ctx, v.AccountID, id)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  	if v.Role == enums.ACCOUNT_ROLE__ADMIN || v.AccountID == ship.AccountID {
   221  		return types.WithResourceOwnership(ctx, ship), nil
   222  	}
   223  
   224  	return nil, status.NoResourcePermission
   225  }
   226  
   227  func (v *CurrentAccount) WithCronJobBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   228  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithCronJobBySFID")
   229  	defer l.End()
   230  
   231  	cronJob, err := cronjob.GetBySFID(ctx, id)
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	ctx = types.WithCronJob(ctx, cronJob)
   236  	return v.WithProjectContextBySFID(ctx, cronJob.ProjectID)
   237  }
   238  
   239  func (v *CurrentAccount) WithOperatorBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   240  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithOperatorBySFID")
   241  	defer l.End()
   242  
   243  	op, err := operator.GetBySFID(ctx, id)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	if v.AccountID != op.AccountID {
   248  		return nil, status.NoOperatorPermission
   249  	}
   250  	return types.WithOperator(ctx, op), nil
   251  }
   252  
   253  func (v *CurrentAccount) WithContractLogBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   254  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithContractLogBySFID")
   255  	defer l.End()
   256  
   257  	cl, err := blockchain.GetContractLogBySFID(ctx, id)
   258  	if err != nil {
   259  		return nil, err
   260  	}
   261  	ctx = types.WithContractLog(ctx, cl)
   262  	return v.WithProjectContextByName(ctx, cl.ProjectName)
   263  }
   264  
   265  func (v *CurrentAccount) WithChainHeightBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   266  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithChainHeightBySFID")
   267  	defer l.End()
   268  
   269  	h, err := blockchain.GetChainHeightBySFID(ctx, id)
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  	ctx = types.WithChainHeight(ctx, h)
   274  	return v.WithProjectContextByName(ctx, h.ProjectName)
   275  }
   276  
   277  func (v *CurrentAccount) WithChainTxBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   278  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithChainTxBySFID")
   279  	defer l.End()
   280  
   281  	t, err := blockchain.GetChainTxBySFID(ctx, id)
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  	ctx = types.WithChainTx(ctx, t)
   286  	return v.WithProjectContextByName(ctx, t.ProjectName)
   287  }
   288  
   289  func (v *CurrentAccount) WithTrafficLimitContextBySFID(ctx context.Context, id types.SFID) (context.Context, error) {
   290  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithTrafficLimitContextBySFID")
   291  	defer l.End()
   292  
   293  	traffic, err := trafficlimit.GetBySFID(ctx, id)
   294  	if err != nil {
   295  		return nil, err
   296  	}
   297  	ctx = types.WithTrafficLimit(ctx, traffic)
   298  	return v.WithProjectContextBySFID(ctx, traffic.ProjectID)
   299  }
   300  
   301  func (v *CurrentAccount) WithTrafficLimitContextBySFIDAndProjectName(ctx context.Context, id types.SFID) (context.Context, error) {
   302  	ctx, l := logr.Start(ctx, "api.mw.CurrentAccount.WithTrafficLimitContextBySFIDAndProjectName")
   303  	defer l.End()
   304  
   305  	traffic, err := trafficlimit.GetBySFID(ctx, id)
   306  	if err != nil {
   307  		return nil, err
   308  	}
   309  	project := types.MustProjectFromContext(ctx)
   310  	if v.Role == enums.ACCOUNT_ROLE__ADMIN || traffic.ProjectID == project.ProjectID {
   311  		return types.WithTrafficLimit(ctx, traffic), nil
   312  	}
   313  
   314  	return nil, status.NoProjectPermission
   315  }