github.com/argoproj/argo-cd@v1.8.7/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  	"fmt"
    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  		min := 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, min, 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  func strftime(t time.Time, cfmt string) string {
   109  	sc := newFlagScanner('%', "", "", cfmt)
   110  	for c, eos := sc.Next(); !eos; c, eos = sc.Next() {
   111  		if !sc.ChangeFlag {
   112  			if sc.HasFlag {
   113  				if v, ok := cDateFlagToGo[c]; ok {
   114  					sc.AppendString(t.Format(v))
   115  				} else {
   116  					switch c {
   117  					case 'w':
   118  						sc.AppendString(fmt.Sprint(int(t.Weekday())))
   119  					default:
   120  						sc.AppendChar('%')
   121  						sc.AppendChar(c)
   122  					}
   123  				}
   124  				sc.HasFlag = false
   125  			} else {
   126  				sc.AppendChar(c)
   127  			}
   128  		}
   129  	}
   130  
   131  	return sc.String()
   132  }
   133  
   134  type flagScanner struct {
   135  	flag       byte
   136  	start      string
   137  	end        string
   138  	buf        []byte
   139  	str        string
   140  	Length     int
   141  	Pos        int
   142  	HasFlag    bool
   143  	ChangeFlag bool
   144  }
   145  
   146  func newFlagScanner(flag byte, start, end, str string) *flagScanner {
   147  	return &flagScanner{flag, start, end, make([]byte, 0, len(str)), str, len(str), 0, false, false}
   148  }
   149  
   150  func (fs *flagScanner) AppendString(str string) { fs.buf = append(fs.buf, str...) }
   151  
   152  func (fs *flagScanner) AppendChar(ch byte) { fs.buf = append(fs.buf, ch) }
   153  
   154  func (fs *flagScanner) String() string { return string(fs.buf) }
   155  
   156  func (fs *flagScanner) Next() (byte, bool) {
   157  	c := byte('\000')
   158  	fs.ChangeFlag = false
   159  	if fs.Pos == fs.Length {
   160  		if fs.HasFlag {
   161  			fs.AppendString(fs.end)
   162  		}
   163  		return c, true
   164  	} else {
   165  		c = fs.str[fs.Pos]
   166  		if c == fs.flag {
   167  			if fs.Pos < (fs.Length-1) && fs.str[fs.Pos+1] == fs.flag {
   168  				fs.HasFlag = false
   169  				fs.AppendChar(fs.flag)
   170  				fs.Pos += 2
   171  				return fs.Next()
   172  			} else if fs.Pos != fs.Length-1 {
   173  				if fs.HasFlag {
   174  					fs.AppendString(fs.end)
   175  				}
   176  				fs.AppendString(fs.start)
   177  				fs.ChangeFlag = true
   178  				fs.HasFlag = true
   179  			}
   180  		}
   181  	}
   182  	fs.Pos++
   183  	return c, false
   184  }