github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/services/authorizations/validate.go (about)

     1  /*
     2   * Copyright 2023 Wang Min Xiang
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   * 	http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   */
    17  
    18  package authorizations
    19  
    20  import (
    21  	"fmt"
    22  	"github.com/aacfactory/errors"
    23  	"github.com/aacfactory/fns/context"
    24  	"github.com/aacfactory/fns/runtime"
    25  	"github.com/aacfactory/fns/services"
    26  	"time"
    27  )
    28  
    29  var (
    30  	validateFnName = []byte("validate")
    31  )
    32  
    33  func ValidateContext(ctx context.Context) (err error) {
    34  	authorization, has, loadErr := Load(ctx)
    35  	if loadErr != nil {
    36  		err = ErrUnauthorized.WithCause(loadErr)
    37  		return
    38  	}
    39  	if has {
    40  		if authorization.Validate() {
    41  			return
    42  		}
    43  		err = ErrUnauthorized
    44  		return
    45  	}
    46  	r := services.LoadRequest(ctx)
    47  	token := r.Header().Token()
    48  	if len(token) == 0 {
    49  		err = ErrUnauthorized
    50  		return
    51  	}
    52  	validated, validErr := Validate(ctx, token)
    53  	if validErr != nil {
    54  		err = validErr
    55  		return
    56  	}
    57  	With(ctx, validated)
    58  	return
    59  }
    60  
    61  func Validate(ctx context.Context, token Token) (authorization Authorization, err error) {
    62  	rt := runtime.Load(ctx)
    63  	response, handleErr := rt.Endpoints().Request(
    64  		ctx,
    65  		endpointName, validateFnName,
    66  		token,
    67  	)
    68  	if handleErr != nil {
    69  		err = handleErr
    70  		return
    71  	}
    72  	authorization, err = services.ValueOfResponse[Authorization](response)
    73  	return
    74  }
    75  
    76  type validateFn struct {
    77  	encoder       TokenEncoder
    78  	store         TokenStore
    79  	autoRefresh   bool
    80  	refreshWindow time.Duration
    81  	expireTTL     time.Duration
    82  }
    83  
    84  func (fn *validateFn) Name() string {
    85  	return string(validateFnName)
    86  }
    87  
    88  func (fn *validateFn) Internal() bool {
    89  	return true
    90  }
    91  
    92  func (fn *validateFn) Readonly() bool {
    93  	return false
    94  }
    95  
    96  func (fn *validateFn) Handle(r services.Request) (v any, err error) {
    97  	param, paramErr := services.ValueOfParam[Token](r.Param())
    98  	if paramErr != nil {
    99  		err = errors.Warning("authorizations: invalid param")
   100  		return
   101  	}
   102  	authorization, decodeErr := fn.encoder.Decode(r, param)
   103  	if decodeErr != nil {
   104  		err = ErrUnauthorized.WithCause(decodeErr)
   105  		return
   106  	}
   107  	stored, has, getErr := fn.store.Get(r, authorization.Account, authorization.Id)
   108  	if getErr != nil {
   109  		err = errors.Warning("authorizations: validate token failed").WithCause(getErr)
   110  		return
   111  	}
   112  	if !has {
   113  		err = errors.Warning("authorizations: validate token failed").WithCause(fmt.Errorf("not exist"))
   114  		return
   115  	}
   116  	if !stored.Validate() {
   117  		err = ErrUnauthorized
   118  		return
   119  	}
   120  	if fn.autoRefresh {
   121  		if authorization.ExpireAT.Sub(time.Now()) < fn.refreshWindow {
   122  			stored.ExpireAT = time.Now().Add(fn.expireTTL)
   123  			saveErr := fn.store.Save(r, stored)
   124  			if saveErr != nil {
   125  				err = errors.Warning("authorizations: validate token failed at refresh").WithCause(saveErr)
   126  				return
   127  			}
   128  		}
   129  	}
   130  	v = stored
   131  	return
   132  }