github.com/argoproj/argo-cd/v3@v3.2.1/util/lua/oslib_safe.go (about)

     1  package lua
     2  
     3  // oslib_safe contains a subset of the lua OS library. For security reasons, we do not expose
     4  // the entirety of lua OS library to custom actions, such as ones which can exit, read files, etc.
     5  // Only the safe functions like os.time(), os.date() are exposed. Implementation was copied from
     6  // github.com/yuin/gopher-lua.
     7  
     8  import (
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  
    13  	lua "github.com/yuin/gopher-lua"
    14  )
    15  
    16  func OpenSafeOs(l *lua.LState) int {
    17  	tabmod := l.RegisterModule(lua.TabLibName, osFuncs)
    18  	l.Push(tabmod)
    19  	return 1
    20  }
    21  
    22  func SafeOsLoader(l *lua.LState) int {
    23  	mod := l.SetFuncs(l.NewTable(), osFuncs)
    24  	l.Push(mod)
    25  	return 1
    26  }
    27  
    28  var osFuncs = map[string]lua.LGFunction{
    29  	"time": osTime,
    30  	"date": osDate,
    31  }
    32  
    33  func osTime(l *lua.LState) int {
    34  	if l.GetTop() == 0 {
    35  		l.Push(lua.LNumber(time.Now().Unix()))
    36  	} else {
    37  		tbl := l.CheckTable(1)
    38  		sec := getIntField(tbl, "sec", 0)
    39  		minutes := getIntField(tbl, "min", 0)
    40  		hour := getIntField(tbl, "hour", 12)
    41  		day := getIntField(tbl, "day", -1)
    42  		month := getIntField(tbl, "month", -1)
    43  		year := getIntField(tbl, "year", -1)
    44  		isdst := getBoolField(tbl, "isdst", false)
    45  		t := time.Date(year, time.Month(month), day, hour, minutes, sec, 0, time.Local)
    46  		// TODO dst
    47  		if false {
    48  			print(isdst)
    49  		}
    50  		l.Push(lua.LNumber(t.Unix()))
    51  	}
    52  	return 1
    53  }
    54  
    55  func getIntField(tb *lua.LTable, key string, v int) int {
    56  	ret := tb.RawGetString(key)
    57  	if ln, ok := ret.(lua.LNumber); ok {
    58  		return int(ln)
    59  	}
    60  	return v
    61  }
    62  
    63  func getBoolField(tb *lua.LTable, key string, v bool) bool {
    64  	ret := tb.RawGetString(key)
    65  	if lb, ok := ret.(lua.LBool); ok {
    66  		return bool(lb)
    67  	}
    68  	return v
    69  }
    70  
    71  func osDate(l *lua.LState) int {
    72  	t := time.Now()
    73  	cfmt := "%c"
    74  	if l.GetTop() >= 1 {
    75  		cfmt = l.CheckString(1)
    76  		if strings.HasPrefix(cfmt, "!") {
    77  			t = time.Now().UTC()
    78  			cfmt = strings.TrimLeft(cfmt, "!")
    79  		}
    80  		if l.GetTop() >= 2 {
    81  			t = time.Unix(l.CheckInt64(2), 0)
    82  		}
    83  		if strings.HasPrefix(cfmt, "*t") {
    84  			ret := l.NewTable()
    85  			ret.RawSetString("year", lua.LNumber(t.Year()))
    86  			ret.RawSetString("month", lua.LNumber(t.Month()))
    87  			ret.RawSetString("day", lua.LNumber(t.Day()))
    88  			ret.RawSetString("hour", lua.LNumber(t.Hour()))
    89  			ret.RawSetString("min", lua.LNumber(t.Minute()))
    90  			ret.RawSetString("sec", lua.LNumber(t.Second()))
    91  			ret.RawSetString("wday", lua.LNumber(t.Weekday()+1))
    92  			// TODO yday & dst
    93  			ret.RawSetString("yday", lua.LNumber(0))
    94  			ret.RawSetString("isdst", lua.LFalse)
    95  			l.Push(ret)
    96  			return 1
    97  		}
    98  	}
    99  	l.Push(lua.LString(strftime(t, cfmt)))
   100  	return 1
   101  }
   102  
   103  var cDateFlagToGo = map[byte]string{
   104  	'a': "mon", 'A': "Monday", 'b': "Jan", 'B': "January", 'c': "02 Jan 06 15:04 MST", 'd': "02",
   105  	'F': "2006-01-02", 'H': "15", 'I': "03", 'm': "01", 'M': "04", 'p': "PM", 'P': "pm", 'S': "05",
   106  	'x': "15/04/05", 'X': "15:04:05", 'y': "06", 'Y': "2006", 'z': "-0700", 'Z': "MST",
   107  }
   108  
   109  func strftime(t time.Time, cfmt string) string {
   110  	sc := newFlagScanner('%', "", "", cfmt)
   111  	for c, eos := sc.Next(); !eos; c, eos = sc.Next() {
   112  		if !sc.ChangeFlag {
   113  			if sc.HasFlag {
   114  				if v, ok := cDateFlagToGo[c]; ok {
   115  					sc.AppendString(t.Format(v))
   116  				} else {
   117  					switch c {
   118  					case 'w':
   119  						sc.AppendString(strconv.Itoa(int(t.Weekday())))
   120  					default:
   121  						sc.AppendChar('%')
   122  						sc.AppendChar(c)
   123  					}
   124  				}
   125  				sc.HasFlag = false
   126  			} else {
   127  				sc.AppendChar(c)
   128  			}
   129  		}
   130  	}
   131  
   132  	return sc.String()
   133  }
   134  
   135  type flagScanner struct {
   136  	flag       byte
   137  	start      string
   138  	end        string
   139  	buf        []byte
   140  	str        string
   141  	Length     int
   142  	Pos        int
   143  	HasFlag    bool
   144  	ChangeFlag bool
   145  }
   146  
   147  func newFlagScanner(flag byte, start, end, str string) *flagScanner {
   148  	return &flagScanner{flag, start, end, make([]byte, 0, len(str)), str, len(str), 0, false, false}
   149  }
   150  
   151  func (fs *flagScanner) AppendString(str string) { fs.buf = append(fs.buf, str...) }
   152  
   153  func (fs *flagScanner) AppendChar(ch byte) { fs.buf = append(fs.buf, ch) }
   154  
   155  func (fs *flagScanner) String() string { return string(fs.buf) }
   156  
   157  func (fs *flagScanner) Next() (byte, bool) {
   158  	c := byte('\000')
   159  	fs.ChangeFlag = false
   160  	if fs.Pos == fs.Length {
   161  		if fs.HasFlag {
   162  			fs.AppendString(fs.end)
   163  		}
   164  		return c, true
   165  	}
   166  	c = fs.str[fs.Pos]
   167  	if c == fs.flag {
   168  		if fs.Pos < (fs.Length-1) && fs.str[fs.Pos+1] == fs.flag {
   169  			fs.HasFlag = false
   170  			fs.AppendChar(fs.flag)
   171  			fs.Pos += 2
   172  			return fs.Next()
   173  		} else if fs.Pos != fs.Length-1 {
   174  			if fs.HasFlag {
   175  				fs.AppendString(fs.end)
   176  			}
   177  			fs.AppendString(fs.start)
   178  			fs.ChangeFlag = true
   179  			fs.HasFlag = true
   180  		}
   181  	}
   182  	fs.Pos++
   183  	return c, false
   184  }