Documentation
¶
Overview ¶
storage defines a storage mechanism
Package storage - Redis-backed implementation of the Storage interface.
This file adds an additive, optional backend used when multiple interactsh server instances need to share state behind a load balancer. It does not replace or alter the default in-memory/LevelDB StorageDB; both backends coexist and the caller decides which one to construct.
storage implements a encrypted memory mechanism
Index ¶
- Variables
- func AESEncrypt(key []byte, message []byte) (string, error)
- func AppendMany(sep string, slices ...[]byte) []byte
- func ParseB64RSAPublicKeyFromPEM(pubPEM string) (*rsa.PublicKey, error)
- type CacheMetrics
- type CorrelationData
- type EvictionStrategy
- type GetInteractionsFunc
- type Options
- type RedisOptions
- type Storage
- type StorageDB
- func (s *StorageDB) AddInteraction(correlationID string, data []byte) error
- func (s *StorageDB) AddInteractionWithId(id string, data []byte) error
- func (s *StorageDB) Close() error
- func (s *StorageDB) GetCacheItem(token string) (*CorrelationData, error)
- func (s *StorageDB) GetCacheMetrics() (*CacheMetrics, error)
- func (s *StorageDB) GetInteractions(correlationID, secret string) ([]string, string, error)
- func (s *StorageDB) GetInteractionsWithId(id string) ([]string, error)
- func (s *StorageDB) GetInteractionsWithIdForConsumer(id, consumerID string) ([]string, error)
- func (s *StorageDB) ListUploads(correlationID string) ([]UploadedFile, bool)
- func (s *StorageDB) RemoveConsumer(id, consumerID string) error
- func (s *StorageDB) RemoveID(correlationID, secret string) error
- func (s *StorageDB) SetID(ID string) error
- func (s *StorageDB) SetIDPublicKey(correlationID, secretKey, publicKey string) error
- func (s *StorageDB) UpdateUploads(correlationID, secret string, fn func([]UploadedFile) ([]UploadedFile, error)) error
- type StorageRedis
- func (s *StorageRedis) AddInteraction(correlationID string, data []byte) error
- func (s *StorageRedis) AddInteractionWithId(id string, data []byte) error
- func (s *StorageRedis) Close() error
- func (s *StorageRedis) GetCacheItem(token string) (*CorrelationData, error)
- func (s *StorageRedis) GetCacheMetrics() (*CacheMetrics, error)
- func (s *StorageRedis) GetInteractions(correlationID, secret string) ([]string, string, error)
- func (s *StorageRedis) GetInteractionsWithId(id string) ([]string, error)
- func (s *StorageRedis) GetInteractionsWithIdForConsumer(id, consumerID string) ([]string, error)
- func (s *StorageRedis) RemoveConsumer(id, consumerID string) error
- func (s *StorageRedis) RemoveID(correlationID, secret string) error
- func (s *StorageRedis) SetID(id string) error
- func (s *StorageRedis) SetIDPublicKey(correlationID, secretKey, publicKey string) error
- type UploadStorage
- type UploadedFile
Constants ¶
This section is empty.
Variables ¶
var DefaultOptions = Options{ MaxSize: 2500000, MaxSharedInteractions: defaultMaxSharedInteractions, EvictionStrategy: EvictionStrategySliding, }
var ErrCorrelationIdNotFound = errkit.New("could not get correlation-id from cache")
var ErrInvalidSecretKey = errkit.New("invalid secret key passed for correlation-id")
ErrInvalidSecretKey is returned when the secret key presented for a correlation-id does not match the one stored at registration. It is distinguishable from ErrCorrelationIdNotFound so callers can tell "wrong session" apart from "no such session".
Functions ¶
func AESEncrypt ¶ added in v1.0.7
AESEncrypt encrypts a message using AES and puts IV at the beginning of ciphertext.
func AppendMany ¶ added in v1.0.7
Types ¶
type CacheMetrics ¶ added in v0.0.5
type CorrelationData ¶
type CorrelationData struct {
sync.Mutex
// data contains data for a correlation-id in AES encrypted json format.
Data []string `json:"data"`
// secretkey is a secret key for original user verification
SecretKey string `json:"-"`
// AESKey is the AES encryption key in encrypted format.
AESKeyEncrypted string `json:"aes-key"`
// decrypted AES key for signing
AESKey []byte `json:"-"`
ReadOffsets map[string]int `json:"-"`
LastSeen map[string]time.Time `json:"-"`
// Files is metadata for files uploaded against this correlation-id.
// Guarded by the embedded Mutex. Not persisted: only interaction blobs
// are written to disk, and uploads do not survive a restart.
Files []UploadedFile `json:"-"`
}
CorrelationData is the data for a correlation-id.
type EvictionStrategy ¶ added in v1.3.0
type EvictionStrategy int
const ( EvictionStrategySliding EvictionStrategy = iota // expire-after-access EvictionStrategyFixed // expire-after-write )
type GetInteractionsFunc ¶ added in v1.0.7
type GetInteractionsFunc func() []string
type Options ¶ added in v1.0.7
type Options struct {
DbPath string
EvictionTTL time.Duration
MaxSize int
EvictionStrategy EvictionStrategy
// OnRemoval is called for each client session removed from cache
// (deregistration, TTL expiry, size eviction, or cache close).
OnRemoval func()
// OnEviction is invoked when a correlation-id leaves the cache for any
// reason: explicit removal, TTL expiry, capacity eviction or Close.
// Unlike OnRemoval it fires for every entry, not just client sessions, and
// receives the evicted data so callers can release resources keyed off it.
// It runs on the cache's single event goroutine and must not block.
OnEviction func(correlationID string, data *CorrelationData)
}
type RedisOptions ¶ added in v1.4.0
type RedisOptions struct {
// URL is a redis connection string, e.g. redis://user:pass@host:6379/0
URL string
// KeyPrefix is prepended to every key. Defaults to "interactsh:".
KeyPrefix string
// TLS, when non-nil, enables TLS with the provided config.
TLS *tls.Config
// EvictionTTL controls how long correlation state survives without activity.
// A value <= 0 disables TTL.
EvictionTTL time.Duration
// EvictionStrategy mirrors storage.Options.EvictionStrategy:
// - sliding: TTL is refreshed on access (default)
// - fixed: TTL is set on write and not refreshed
EvictionStrategy EvictionStrategy
// consumers share an id. <= 0 means unlimited.
MaxSharedInteractions int
// Client is an already-configured *redis.Client. If set, URL/TLS are ignored.
// Useful for tests with miniredis.
Client *redis.Client
}
RedisOptions configures the Redis-backed Storage.
All eviction-related fields mirror the semantics of the local Options struct; they are duplicated here intentionally so that adding the Redis backend does not touch the existing Options/StorageDB code paths.
type Storage ¶
type Storage interface {
GetCacheMetrics() (*CacheMetrics, error)
SetIDPublicKey(correlationID, secretKey, publicKey string) error
SetID(ID string) error
AddInteraction(correlationID string, data []byte) error
AddInteractionWithId(id string, data []byte) error
GetInteractions(correlationID, secret string) ([]string, string, error)
GetInteractionsWithId(id string) ([]string, error)
GetInteractionsWithIdForConsumer(id, consumerID string) ([]string, error)
RemoveConsumer(id, consumerID string) error
RemoveID(correlationID, secret string) error
GetCacheItem(token string) (*CorrelationData, error)
Close() error
}
type StorageDB ¶ added in v1.0.7
type StorageDB struct {
Options *Options
// contains filtered or unexported fields
}
Storage is an storage for interactsh interaction data as well as correlation-id -> rsa-public-key data.
func (*StorageDB) AddInteraction ¶ added in v1.0.7
AddInteraction adds an interaction data to the correlation ID after encrypting it with Public Key for the provided correlation ID.
func (*StorageDB) AddInteractionWithId ¶ added in v1.0.7
AddInteractionWithId adds an interaction data to the id bucket
func (*StorageDB) GetCacheItem ¶ added in v1.0.7
func (s *StorageDB) GetCacheItem(token string) (*CorrelationData, error)
GetCacheItem returns an item as is
func (*StorageDB) GetCacheMetrics ¶ added in v1.0.7
func (s *StorageDB) GetCacheMetrics() (*CacheMetrics, error)
func (*StorageDB) GetInteractions ¶ added in v1.0.7
GetInteractions returns the interactions for a correlationID and removes it from the storage. It also returns AES Encrypted Key for the IDs.
func (*StorageDB) GetInteractionsWithId ¶ added in v1.0.7
GetInteractions returns the interactions for a id and empty the cache
func (*StorageDB) GetInteractionsWithIdForConsumer ¶ added in v1.3.1
GetInteractionsWithIdForConsumer returns unseen interactions for a consumer using per-consumer read offsets.
func (*StorageDB) ListUploads ¶ added in v1.4.0
func (s *StorageDB) ListUploads(correlationID string) ([]UploadedFile, bool)
ListUploads returns the upload metadata for a correlation-id. No secret is required: this backs the file-serving path, where possession of the correlation-id is the only credential.
func (*StorageDB) RemoveConsumer ¶ added in v1.3.1
RemoveConsumer removes a consumer's read offset and compacts consumed data.
func (*StorageDB) RemoveID ¶ added in v1.0.7
RemoveID removes data for a correlation ID and data related to it.
func (*StorageDB) SetIDPublicKey ¶ added in v1.0.7
SetIDPublicKey sets the correlation ID and publicKey into the cache for further operations.
func (*StorageDB) UpdateUploads ¶ added in v1.4.0
func (s *StorageDB) UpdateUploads(correlationID, secret string, fn func([]UploadedFile) ([]UploadedFile, error)) error
UpdateUploads verifies the secret key for a correlation-id and then runs fn while holding that correlation-id's lock, replacing the upload metadata with whatever fn returns. Callers perform their disk writes inside fn so that the quota check and the commit are atomic with respect to concurrent uploads against the same session.
type StorageRedis ¶ added in v1.4.0
type StorageRedis struct {
// contains filtered or unexported fields
}
StorageRedis implements Storage backed by a Redis server (or compatible).
Key layout (all keys are placed in the same hash slot via the {id} hash tag so the implementation is safe under Redis Cluster as well):
<prefix>meta:{<id>} HASH secret, aes_key, aes_key_enc
<prefix>data:{<id>} LIST ordered AES-encrypted interaction strings
<prefix>consumers:{<id>} SET consumer ids currently subscribed
<prefix>off:{<id>}:<cid> STRING per-consumer read offset (integer)
<prefix>seen:{<id>}:<cid> STRING per-consumer last-seen unix nano
func NewRedis ¶ added in v1.4.0
func NewRedis(options *RedisOptions) (*StorageRedis, error)
NewRedis builds a Redis-backed Storage. The caller is responsible for keeping the underlying Redis server reachable for the lifetime of the returned instance.
func (*StorageRedis) AddInteraction ¶ added in v1.4.0
func (s *StorageRedis) AddInteraction(correlationID string, data []byte) error
AddInteraction encrypts and appends an interaction for the given correlation id.
func (*StorageRedis) AddInteractionWithId ¶ added in v1.4.0
func (s *StorageRedis) AddInteractionWithId(id string, data []byte) error
AddInteractionWithId mirrors AddInteraction; the distinction in the original StorageDB is purely semantic.
func (*StorageRedis) Close ¶ added in v1.4.0
func (s *StorageRedis) Close() error
Close releases the redis client. Existing data in Redis is preserved so that the next instance can resume; this matches the multi-instance use case the Redis backend was introduced for.
func (*StorageRedis) GetCacheItem ¶ added in v1.4.0
func (s *StorageRedis) GetCacheItem(token string) (*CorrelationData, error)
GetCacheItem returns the CorrelationData associated with the token. Only the fields stored in the meta hash are populated; per-consumer offsets live in separate keys.
func (*StorageRedis) GetCacheMetrics ¶ added in v1.4.0
func (s *StorageRedis) GetCacheMetrics() (*CacheMetrics, error)
func (*StorageRedis) GetInteractions ¶ added in v1.4.0
func (s *StorageRedis) GetInteractions(correlationID, secret string) ([]string, string, error)
GetInteractions returns all buffered interactions for the correlation id and atomically clears the buffer (preserving the legacy single-consumer semantics of GetInteractions).
func (*StorageRedis) GetInteractionsWithId ¶ added in v1.4.0
func (s *StorageRedis) GetInteractionsWithId(id string) ([]string, error)
GetInteractionsWithId returns and drains the buffered interactions for an id.
func (*StorageRedis) GetInteractionsWithIdForConsumer ¶ added in v1.4.0
func (s *StorageRedis) GetInteractionsWithIdForConsumer(id, consumerID string) ([]string, error)
GetInteractionsWithIdForConsumer returns unseen interactions for the given consumer, advancing its offset and evicting stale consumers atomically via a Lua script.
func (*StorageRedis) RemoveConsumer ¶ added in v1.4.0
func (s *StorageRedis) RemoveConsumer(id, consumerID string) error
RemoveConsumer drops the consumer's offset/last-seen tracking and compacts the underlying data list when possible.
func (*StorageRedis) RemoveID ¶ added in v1.4.0
func (s *StorageRedis) RemoveID(correlationID, secret string) error
RemoveID drops every key associated with the correlation id after secret verification.
func (*StorageRedis) SetID ¶ added in v1.4.0
func (s *StorageRedis) SetID(id string) error
SetID registers a correlation id without an associated public key. Used for the wildcard / auth-token path.
func (*StorageRedis) SetIDPublicKey ¶ added in v1.4.0
func (s *StorageRedis) SetIDPublicKey(correlationID, secretKey, publicKey string) error
SetIDPublicKey registers a correlation id along with its RSA public key. Any pre-existing keyspace for the id is cleared first to mirror the StorageDB behaviour after cache eviction + session restore.
type UploadStorage ¶ added in v1.4.0
type UploadStorage interface {
// UpdateUploads verifies the secret key for a correlation-id and then runs
// fn under that correlation-id's lock, replacing the upload metadata with
// whatever fn returns. Callers perform their disk writes inside fn so the
// quota check and the commit are atomic against concurrent uploads for the
// same session. fn is invoked at most once.
UpdateUploads(correlationID, secret string, fn func([]UploadedFile) ([]UploadedFile, error)) error
// ListUploads returns the upload metadata for a correlation-id, and whether
// the correlation-id is known at all.
ListUploads(correlationID string) ([]UploadedFile, bool)
}
UploadStorage is the optional capability of tracking per-session uploaded file metadata, implemented by StorageDB.
It is deliberately kept out of Storage. The uploaded bytes live on the local filesystem of a single server instance and the capacity quota is an in-process counter, so the feature is only coherent for instance-local backends. A shared backend such as Redis would let one instance advertise files whose bytes only exist on another instance's disk, so it does not implement this and file hosting is refused when it is selected.
type UploadedFile ¶ added in v1.4.0
type UploadedFile struct {
Name string `json:"name"`
Size int64 `json:"size"`
SHA256 string `json:"sha256"`
Timestamp time.Time `json:"timestamp"`
}
UploadedFile is metadata for a file uploaded by the owner of a correlation-id. The bytes themselves live on disk, managed by the server's upload store; this record exists so that cache eviction and deregistration can drive file cleanup.