Skip to content

Commit

Permalink
Set time variables in transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
Yehor Komarov committed Nov 18, 2024
1 parent 05c7d39 commit 6ebf213
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 9 deletions.
18 changes: 18 additions & 0 deletions internal/corazawaf/rule_multiphase.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ func minPhase(v variables.RuleVariable) types.RulePhase {
return types.PhaseResponseHeaders
case variables.UniqueID:
return types.PhaseRequestHeaders
case variables.Time:
return types.PhaseRequestHeaders
case variables.TimeDay:
return types.PhaseRequestHeaders
case variables.TimeEpoch:
return types.PhaseRequestHeaders
case variables.TimeHour:
return types.PhaseRequestHeaders
case variables.TimeMin:
return types.PhaseRequestHeaders
case variables.TimeMon:
return types.PhaseRequestHeaders
case variables.TimeSec:
return types.PhaseRequestHeaders
case variables.TimeWday:
return types.PhaseRequestHeaders
case variables.TimeYear:
return types.PhaseRequestHeaders
case variables.ArgsCombinedSize:
// Size changes between phase 1 and 2 so evaluate both times
return types.PhaseRequestHeaders
Expand Down
77 changes: 77 additions & 0 deletions internal/corazawaf/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,24 @@ func (tx *Transaction) Collection(idx variables.RuleVariable) collection.Collect
return tx.variables.multipartPartHeaders
case variables.MultipartStrictError:
return tx.variables.multipartStrictError
case variables.Time:
return tx.variables.time
case variables.TimeDay:
return tx.variables.timeDay
case variables.TimeEpoch:
return tx.variables.timeEpoch
case variables.TimeHour:
return tx.variables.timeHour
case variables.TimeMin:
return tx.variables.timeMin
case variables.TimeMon:
return tx.variables.timeMon
case variables.TimeSec:
return tx.variables.timeSec
case variables.TimeWday:
return tx.variables.timeWday
case variables.TimeYear:
return tx.variables.timeYear
}

return collections.Noop
Expand Down Expand Up @@ -1591,6 +1609,20 @@ func (tx *Transaction) generateResponseBodyError(err error) {
tx.variables.resBodyProcessorErrorMsg.Set(err.Error())
}

// setTimeVariables generates all the time variables
func (tx *Transaction) setTimeVariables() {
timestamp := time.Unix(0, tx.Timestamp)
tx.variables.time.Set(timestamp.Format(time.TimeOnly))
tx.variables.timeDay.Set(strconv.Itoa(timestamp.Day()))
tx.variables.timeEpoch.Set(strconv.FormatInt(timestamp.Unix(), 10))
tx.variables.timeHour.Set(strconv.Itoa(timestamp.Hour()))
tx.variables.timeMin.Set(strconv.Itoa(timestamp.Minute()))
tx.variables.timeSec.Set(strconv.Itoa(timestamp.Second()))
tx.variables.timeWday.Set(strconv.Itoa(int(timestamp.Weekday())))
tx.variables.timeMon.Set(strconv.Itoa(int(timestamp.Month()) - 1))
tx.variables.timeYear.Set(strconv.Itoa(timestamp.Year()))
}

// TransactionVariables has pointers to all the variables of the transaction
type TransactionVariables struct {
args *collections.ConcatKeyed
Expand Down Expand Up @@ -1669,6 +1701,15 @@ type TransactionVariables struct {
resBodyErrorMsg *collections.Single
resBodyProcessorError *collections.Single
resBodyProcessorErrorMsg *collections.Single
time *collections.Single
timeDay *collections.Single
timeEpoch *collections.Single
timeHour *collections.Single
timeMin *collections.Single
timeMon *collections.Single
timeSec *collections.Single
timeWday *collections.Single
timeYear *collections.Single
}

func NewTransactionVariables() *TransactionVariables {
Expand Down Expand Up @@ -1741,6 +1782,15 @@ func NewTransactionVariables() *TransactionVariables {
v.requestXML = collections.NewMap(variables.RequestXML)
v.multipartPartHeaders = collections.NewMap(variables.MultipartPartHeaders)
v.multipartStrictError = collections.NewSingle(variables.MultipartStrictError)
v.time = collections.NewSingle(variables.Time)
v.timeDay = collections.NewSingle(variables.TimeDay)
v.timeEpoch = collections.NewSingle(variables.TimeEpoch)
v.timeHour = collections.NewSingle(variables.TimeHour)
v.timeMin = collections.NewSingle(variables.TimeMin)
v.timeMon = collections.NewSingle(variables.TimeMon)
v.timeSec = collections.NewSingle(variables.TimeSec)
v.timeWday = collections.NewSingle(variables.TimeWday)
v.timeYear = collections.NewSingle(variables.TimeYear)

// XML is a pointer to RequestXML
v.xml = v.requestXML
Expand Down Expand Up @@ -2299,6 +2349,33 @@ func (v *TransactionVariables) All(f func(v variables.RuleVariable, col collecti
if !f(variables.XML, v.xml) {
return
}
if !f(variables.Time, v.time) {
return
}
if !f(variables.TimeDay, v.timeDay) {
return
}
if !f(variables.TimeEpoch, v.timeEpoch) {
return
}
if !f(variables.TimeHour, v.timeHour) {
return
}
if !f(variables.TimeMin, v.timeMin) {
return
}
if !f(variables.TimeMon, v.timeMon) {
return
}
if !f(variables.TimeSec, v.timeSec) {
return
}
if !f(variables.TimeWday, v.timeWday) {
return
}
if !f(variables.TimeYear, v.timeYear) {
return
}
}

type formattable interface {
Expand Down
30 changes: 30 additions & 0 deletions internal/corazawaf/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"strconv"
"strings"
"testing"
"time"

"github.com/corazawaf/coraza/v3/collection"
"github.com/corazawaf/coraza/v3/debuglog"
Expand Down Expand Up @@ -67,6 +68,23 @@ func TestTxSetters(t *testing.T) {

validateMacroExpansion(exp, tx, t)
}

func TestTxTime(t *testing.T) {
tx := makeTransactionTimestamped(t)
exp := map[string]string{
"%{TIME}": "15:27:34",
"%{TIME_DAY}": "18",
"%{TIME_EPOCH}": fmt.Sprintf("%d", tx.Timestamp/1e9), // 1731943654 in UTC, may differ in local timezone
"%{TIME_HOUR}": "15",
"%{TIME_MIN}": "27",
"%{TIME_MON}": "10",
"%{TIME_SEC}": "34",
"%{TIME_WDAY}": "1",
"%{TIME_YEAR}": "2024",
}
validateMacroExpansion(exp, tx, t)
}

func TestTxMultipart(t *testing.T) {
tx := NewWAF().NewTransaction()
body := []string{
Expand Down Expand Up @@ -1360,6 +1378,18 @@ func makeTransaction(t testing.TB) *Transaction {
return tx
}

func makeTransactionTimestamped(t testing.TB) *Transaction {
t.Helper()
tx := NewWAF().NewTransaction()
timestamp, err := time.ParseInLocation(time.DateTime, "2024-11-18 15:27:34", time.Local)
if err != nil {
panic(err)
}
tx.Timestamp = timestamp.UnixNano()
tx.setTimeVariables()
return tx
}

func makeTransactionMultipart(t *testing.T) *Transaction {
if t != nil {
t.Helper()
Expand Down
1 change: 1 addition & 0 deletions internal/corazawaf/waf.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ func (w *WAF) newTransaction(opts Options) *Transaction {
tx.variables.duration.Set("0")
tx.variables.highestSeverity.Set("0")
tx.variables.uniqueID.Set(tx.id)
tx.setTimeVariables()

tx.debugLogger.Debug().Msg("Transaction started")

Expand Down
18 changes: 9 additions & 9 deletions internal/variables/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,22 +236,22 @@ const (
ResBodyProcessorError
// ResBodyProcessorErrorMsg
ResBodyProcessorErrorMsg
// Time
// Time holds a formatted string representing the time (hour:minute:second).
Time
// TimeDay
// TimeDay holds the current day of the month (1-31)
TimeDay
// TimeEpoch
// TimeEpoch holds the time in seconds since 1970
TimeEpoch
// TimeHour
// TimeHour holds the current hour of the day (0-23)
TimeHour
// TimeMin
// TimeMin holds the current minute of the hour (0-59)
TimeMin
// TimeMon
// TimeMon holds the current month of the year (0-11)
TimeMon
// TimeSec
// TimeSec holds the current second of the minute (0-59)
TimeSec
// TimeWday
// TimeWday holds the current weekday value (1–7), where Monday is 1
TimeWday
// TimeYear
// TimeYear the current four-digit year value
TimeYear
)

0 comments on commit 6ebf213

Please sign in to comment.