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 }