github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/services/authorizations/encoding.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 "bytes" 22 "encoding/base64" 23 "github.com/aacfactory/avro" 24 "github.com/aacfactory/errors" 25 "github.com/aacfactory/fns/commons/signatures" 26 "github.com/aacfactory/fns/context" 27 "github.com/aacfactory/fns/services" 28 "strings" 29 ) 30 31 type TokenEncoder interface { 32 services.Component 33 Encode(ctx context.Context, param Authorization) (token Token, err error) 34 Decode(ctx context.Context, token Token) (result Authorization, err error) 35 } 36 37 type defaultTokenEncoderConfig struct { 38 Key string `json:"key" avro:"key"` 39 } 40 41 func DefaultTokenEncoder() TokenEncoder { 42 return &defaultTokenEncoder{} 43 } 44 45 type defaultTokenEncoder struct { 46 signature signatures.Signature 47 } 48 49 func (encoder *defaultTokenEncoder) Name() (name string) { 50 return "authorizations:encoder:default" 51 } 52 53 func (encoder *defaultTokenEncoder) Construct(options services.Options) (err error) { 54 config := defaultTokenEncoderConfig{} 55 configErr := options.Config.As(&config) 56 if configErr != nil { 57 err = errors.Warning("authorizations: build default token encoder failed").WithMeta("encoder", encoder.Name()).WithCause(configErr) 58 return 59 } 60 key := strings.TrimSpace(config.Key) 61 if key == "" { 62 err = errors.Warning("authorizations: build default token encoder failed").WithMeta("encoder", encoder.Name()).WithCause(errors.Warning("key is require")) 63 return 64 } 65 encoder.signature = signatures.HMAC([]byte(key)) 66 return 67 } 68 69 func (encoder *defaultTokenEncoder) Shutdown(_ context.Context) { 70 return 71 } 72 73 func (encoder *defaultTokenEncoder) Encode(_ context.Context, param Authorization) (token Token, err error) { 74 p, encodeErr := avro.Marshal(param) 75 if encodeErr != nil { 76 err = errors.Warning("authorizations: encode token failed").WithMeta("encoder", encoder.Name()).WithCause(encodeErr) 77 return 78 } 79 pb := make([]byte, base64.URLEncoding.EncodedLen(len(p))) 80 base64.URLEncoding.Encode(pb, p) 81 pbl := len(pb) 82 83 s := encoder.signature.Sign(p) 84 sb := make([]byte, base64.URLEncoding.EncodedLen(len(s))) 85 base64.URLEncoding.Encode(sb, s) 86 sbl := len(sb) 87 88 token = make(Token, 4+pbl+1+sbl) 89 token[0] = 'F' 90 token[1] = 'n' 91 token[2] = 's' 92 token[3] = ' ' 93 94 copy(token[4:4+pbl], pb) 95 token[4+pbl] = '.' 96 copy(token[4+pbl+1:], sb) 97 98 return 99 } 100 101 func (encoder *defaultTokenEncoder) Decode(_ context.Context, token Token) (result Authorization, err error) { 102 if len(token) < 4 { 103 err = errors.Warning("authorizations: decode token failed").WithMeta("encoder", encoder.Name()).WithCause(errors.Warning("token is invalid")) 104 return 105 } 106 after, found := bytes.CutPrefix(token, []byte{'F', 'n', 's', ' '}) 107 if !found { 108 err = errors.Warning("authorizations: decode token failed").WithMeta("encoder", encoder.Name()).WithCause(errors.Warning("token is invalid")) 109 return 110 } 111 pos := bytes.IndexByte(after, '.') 112 if pos < 1 { 113 err = errors.Warning("authorizations: decode token failed").WithMeta("encoder", encoder.Name()).WithCause(errors.Warning("token is invalid")) 114 return 115 } 116 p, pErr := base64.URLEncoding.DecodeString(string(after[0:pos])) 117 if pErr != nil { 118 err = errors.Warning("authorizations: decode token failed").WithMeta("encoder", encoder.Name()).WithCause(pErr) 119 return 120 } 121 s, sErr := base64.URLEncoding.DecodeString(string(after[pos+1:])) 122 if sErr != nil { 123 err = errors.Warning("authorizations: decode token failed").WithMeta("encoder", encoder.Name()).WithCause(sErr) 124 return 125 } 126 if !encoder.signature.Verify(p, s) { 127 err = errors.Warning("authorizations: decode token failed").WithMeta("encoder", encoder.Name()).WithCause(errors.Warning("token is invalid")) 128 return 129 } 130 decodeErr := avro.Unmarshal(p, &result) 131 if decodeErr != nil { 132 err = errors.Warning("authorizations: decode token failed").WithMeta("encoder", encoder.Name()).WithCause(decodeErr) 133 return 134 } 135 return 136 }