Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ INPUT:
-lip, -listen-ip string public ip address to listen on (default "0.0.0.0")
-e, -eviction int number of days to persist interaction data in memory (default 30)
-ne, -no-eviction disable periodic data eviction from memory
-es, -eviction-strategy string eviction strategy for interactions (sliding, fixed) (default "sliding")
-a, -auth enable authentication to server using random generated token
-t, -token string enable authentication to server using given token
-acao-url string origin url to send in acao header to use web-client) (default "*")
Expand Down
14 changes: 14 additions & 0 deletions cmd/interactsh-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func main() {
flagSet.StringVarP(&cliOptions.ListenIP, "listen-ip", "lip", "0.0.0.0", "public ip address to listen on"),
flagSet.IntVarP(&cliOptions.Eviction, "eviction", "e", 30, "number of days to persist interaction data in memory"),
flagSet.BoolVarP(&cliOptions.NoEviction, "no-eviction", "ne", false, "disable periodic data eviction from memory"),
flagSet.StringVarP(&cliOptions.EvictionStrategy, "eviction-strategy", "es", "sliding", "eviction strategy for interactions (sliding, fixed)"),
flagSet.BoolVarP(&cliOptions.Auth, "auth", "a", false, "enable authentication to server using random generated token"),
flagSet.StringVarP(&cliOptions.Token, "token", "t", "", "enable authentication to server using given token"),
flagSet.StringVar(&cliOptions.OriginURL, "acao-url", "*", "origin url to send in acao header to use web-client)"), // cli flag set to deprecate
Expand Down Expand Up @@ -218,9 +219,22 @@ func main() {
if cliOptions.NoEviction {
evictionTTL = -1
}

// Parse eviction strategy
var evictionStrategy storage.EvictionStrategy
switch strings.ToLower(cliOptions.EvictionStrategy) {
case "fixed":
evictionStrategy = storage.EvictionStrategyFixed
case "sliding":
evictionStrategy = storage.EvictionStrategySliding
default:
gologger.Fatal().Msgf("invalid eviction strategy '%s', must be 'sliding' or 'fixed'\n", cliOptions.EvictionStrategy)
}

var store storage.Storage
storeOptions := storage.DefaultOptions
storeOptions.EvictionTTL = evictionTTL
storeOptions.EvictionStrategy = evictionStrategy
if cliOptions.DiskStorage {
if cliOptions.DiskStoragePath == "" {
gologger.Fatal().Msgf("disk storage path must be specified\n")
Expand Down
1 change: 1 addition & 0 deletions pkg/options/server_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type CLIServerOptions struct {
LdapWithFullLogger bool
Eviction int
NoEviction bool
EvictionStrategy string
Responder bool
Smb bool
SmbPort int
Expand Down
17 changes: 13 additions & 4 deletions pkg/storage/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@ package storage

import "time"

type EvictionStrategy int

const (
EvictionStrategySliding EvictionStrategy = iota // expire-after-access
EvictionStrategyFixed // expire-after-write
)

type Options struct {
DbPath string
EvictionTTL time.Duration
MaxSize int
DbPath string
EvictionTTL time.Duration
MaxSize int
EvictionStrategy EvictionStrategy
}

func (options *Options) UseDisk() bool {
return options.DbPath != ""
}

var DefaultOptions = Options{
MaxSize: 2500000,
MaxSize: 2500000,
EvictionStrategy: EvictionStrategySliding,
}
9 changes: 8 additions & 1 deletion pkg/storage/storagedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ func New(options *Options) (*StorageDB, error) {
cache.WithMaximumSize(options.MaxSize),
}
if options.EvictionTTL > 0 {
cacheOptions = append(cacheOptions, cache.WithExpireAfterAccess(options.EvictionTTL))
switch options.EvictionStrategy {
case EvictionStrategyFixed:
cacheOptions = append(cacheOptions, cache.WithExpireAfterWrite(options.EvictionTTL))
case EvictionStrategySliding:
fallthrough
default:
cacheOptions = append(cacheOptions, cache.WithExpireAfterAccess(options.EvictionTTL))
}
}
if options.UseDisk() {
cacheOptions = append(cacheOptions, cache.WithRemovalListener(storageDB.OnCacheRemovalCallback))
Expand Down
46 changes: 46 additions & 0 deletions pkg/storage/storagedb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,49 @@ func doStuffWithOtherCache(cache cache.Cache) {
_, _ = cache.GetIfPresent(strconv.Itoa(i))
}
}

func TestSlidingEvictionStrategy(t *testing.T) {
testTTL := 100 * time.Millisecond
smallDelay := 10 * time.Millisecond
mem, err := New(&Options{EvictionTTL: testTTL, EvictionStrategy: EvictionStrategySliding})
require.Nil(t, err)
defer mem.Close()

err = mem.SetID("test-sliding")
require.Nil(t, err)

// Access after half TTL - should extend expiration
time.Sleep(testTTL / 2)
_, ok := mem.cache.GetIfPresent("test-sliding")
require.True(t, ok)

// Still present after original TTL due to sliding window
time.Sleep(testTTL / 2 + smallDelay)
_, ok = mem.cache.GetIfPresent("test-sliding")
require.True(t, ok)

// Should be expired after full TTL despite access
time.Sleep(testTTL + smallDelay)
_, ok = mem.cache.GetIfPresent("test-sliding")
require.False(t, ok)
}

func TestFixedEvictionStrategy(t *testing.T) {
testTTL := 100 * time.Millisecond
mem, err := New(&Options{EvictionTTL: testTTL, EvictionStrategy: EvictionStrategyFixed})
require.Nil(t, err)
defer mem.Close()

err = mem.SetID("test-fixed")
require.Nil(t, err)

// Access after half TTL - should NOT extend expiration
time.Sleep(testTTL / 2)
_, ok := mem.cache.GetIfPresent("test-fixed")
require.True(t, ok)

// Should be expired after full TTL despite access
time.Sleep(testTTL / 2 + 10 * time.Millisecond)
_, ok = mem.cache.GetIfPresent("test-fixed")
require.False(t, ok)
}
Loading