diff --git a/otpmanagermdl/otpmanagermdl.go b/otpmanagermdl/otpmanagermdl.go new file mode 100644 index 0000000000000000000000000000000000000000..704418302bb8cdba538f85516655a5baee9abba0 --- /dev/null +++ b/otpmanagermdl/otpmanagermdl.go @@ -0,0 +1,109 @@ +package otpmanagermdl + +import ( + "errors" + "time" + + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" + + "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/cachemdl" +) + +// Entry is a data to be stored against a key. +type Entry struct { + Data gjson.Result `json:"data,omitempty"` + Expiration int64 `json:"expiration,omitempty"` + ExpiredAT int64 `json:"expiredAt,omitempty"` +} + +const ( + // keys for the entry object + KEY_DATA = "data" + KEY_EXPIREDAT = "expiredAt" + KEY_EXPIRATION = "expiration" +) + +var store cachemdl.Cacher + +var ErrOtpNotFound = errors.New("OTP_NOT_FOUND") +var ErrInvalidDataType = errors.New("INVALID_DATA_Type") + +// Init initializes otp manager with provided cache. Subsequent calls will not have any effect after first initialization. +func Init(cache cachemdl.Cacher) { + if store != nil { + return + } + + store = cache +} + +// NewEntry prepares the object required to store data in session. +// +// The `exp` field interprets time in seconds. Ex. For 5 seconds, set `5` +func NewOTPEntry(val gjson.Result, exp int64) Entry { + duration := time.Duration(exp) * time.Second + deadLine := time.Now().Add(duration).Unix() + return Entry{ + Data: val, + Expiration: exp, + ExpiredAT: deadLine, + } +} + +// NewRedisEntry prepares the entry for redis cache. This is required because redis accepts a byte array. +func NewRedisEntry(entry Entry) string { + var data string + data, _ = sjson.Set(data, KEY_DATA, entry.Data.Value()) + data, _ = sjson.Set(data, KEY_EXPIRATION, entry.Expiration) + data, _ = sjson.Set(data, KEY_EXPIREDAT, entry.ExpiredAT) + + return data +} + +// Store adds/ updates the entry against the provided key. +func Store(key string, entry Entry) { + duration := time.Duration(entry.Expiration) * time.Second + // if otp manager uses redis cache, the data field (gjson.Result) is saved as is. + // This adds irrelevant fields in redis cache and we get them on retrieve operation. + // The following operation needs to be performed so that the data is marshaled correctly. Redis only accepts []byte{}. + if store.Type() == cachemdl.TypeRedisCache { + store.SetWithExpiration(key, NewRedisEntry(entry), duration) + return + } + store.SetWithExpiration(key, entry, duration) +} + +// // Delete removes the otp entry. If the key is not present, error `ErrOtpNotFound` will be thrown. Caller can ignore error if this is acceptable. +func DeleteOTP(key string) error { + _, ok := store.Get(key) + if !ok { + return ErrOtpNotFound + } + + store.Delete(key) + return nil +} + +func GetOTP(key string) (Entry, bool) { + data, ok := store.Get(key) + if !ok { + return Entry{}, false + } + + switch v := data.(type) { + case string: // for result from redis cache + res := gjson.Parse(v) + return Entry{ + Data: res.Get(KEY_DATA), + Expiration: res.Get(KEY_EXPIRATION).Int(), + ExpiredAT: res.Get(KEY_EXPIREDAT).Int(), + }, true + + case Entry: // for result from fastcache + return v, true + + default: + return Entry{}, false + } +}