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 }