console.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "os"
  7. "strings"
  8. "imuslab.com/arozos/mod/utils"
  9. )
  10. // Handle console command from the console module
  11. func consoleCommandHandler(input string) string {
  12. //chunk := strings.Split(input, " ");
  13. chunk, err := parseCommandLine(input)
  14. if err != nil {
  15. return err.Error()
  16. }
  17. if len(chunk) > 0 && chunk[0] == "auth" {
  18. if matchSubfix(chunk, []string{"auth", "new"}, 4, "auth new {username} {password}") {
  19. return "Creating a new user " + chunk[2] + " with password " + chunk[3]
  20. } else if matchSubfix(chunk, []string{"auth", "dump"}, 4, "auth dump {filename}.csv") {
  21. filename := chunk[2]
  22. fmt.Println("Dumping user list to " + filename + " csv file")
  23. csv := authAgent.ExportUserListAsCSV()
  24. err := os.WriteFile(filename, []byte(csv), 0755)
  25. if err != nil {
  26. return err.Error()
  27. }
  28. return "OK"
  29. }
  30. } else if len(chunk) > 0 && chunk[0] == "permission" {
  31. if matchSubfix(chunk, []string{"permission", "list"}, 2, "") {
  32. fmt.Println("> ", permissionHandler.PermissionGroups)
  33. return "OK"
  34. } else if matchSubfix(chunk, []string{"permission", "user"}, 3, "permission user {username}") {
  35. username := chunk[2]
  36. group, _ := permissionHandler.GetUsersPermissionGroup(username)
  37. for _, thisGroup := range group {
  38. fmt.Println(thisGroup)
  39. }
  40. return "OK"
  41. } else if matchSubfix(chunk, []string{"permission", "group"}, 3, "permission group {groupname}") {
  42. groupname := chunk[2]
  43. groups := permissionHandler.PermissionGroups
  44. for _, thisGroup := range groups {
  45. if thisGroup.Name == groupname {
  46. fmt.Println(thisGroup)
  47. }
  48. }
  49. return "OK"
  50. } else if matchSubfix(chunk, []string{"permission", "getinterface"}, 3, "permission getinterface {username}") {
  51. //Get the list of interface module for this user
  52. userinfo, err := userHandler.GetUserInfoFromUsername(chunk[2])
  53. if err != nil {
  54. return err.Error()
  55. }
  56. return strings.Join(userinfo.GetInterfaceModules(), ",")
  57. }
  58. } else if len(chunk) > 0 && chunk[0] == "quota" {
  59. if matchSubfix(chunk, []string{"quota", "user"}, 3, "quota user {username}") {
  60. userinfo, err := userHandler.GetUserInfoFromUsername(chunk[2])
  61. if err != nil {
  62. return err.Error()
  63. }
  64. fmt.Println("> "+"User Quota: ", userinfo.StorageQuota.UsedStorageQuota, "/", userinfo.StorageQuota.GetUserStorageQuota(), "bytes")
  65. return "OK"
  66. }
  67. } else if len(chunk) > 0 && chunk[0] == "database" {
  68. if matchSubfix(chunk, []string{"database", "dump"}, 3, "database dump {filename}") {
  69. //Dump the database to file
  70. return "WIP"
  71. } else if matchSubfix(chunk, []string{"database", "list", "tables"}, 3, "") {
  72. //List all opened tables
  73. sysdb.Tables.Range(func(k, v interface{}) bool {
  74. fmt.Println(k.(string))
  75. return true
  76. })
  77. return "OK"
  78. } else if matchSubfix(chunk, []string{"database", "view"}, 3, "database list {tablename}") {
  79. //List everything in this table
  80. tableList := []string{}
  81. sysdb.Tables.Range(func(k, v interface{}) bool {
  82. tableList = append(tableList, k.(string))
  83. return true
  84. })
  85. if !utils.StringInArray(tableList, chunk[2]) {
  86. return "Table not exists"
  87. } else if chunk[2] == "auth" {
  88. return "You cannot view this database table"
  89. }
  90. entries, err := sysdb.ListTable(chunk[2])
  91. if err != nil {
  92. return err.Error()
  93. }
  94. for _, keypairs := range entries {
  95. fmt.Println("> " + string(keypairs[0]) + ":" + string(keypairs[1]))
  96. }
  97. fmt.Println("Total Entry Count: ", len(entries))
  98. return "OK"
  99. }
  100. } else if len(chunk) > 0 && chunk[0] == "user" {
  101. if matchSubfix(chunk, []string{"user", "object", "dump"}, 4, "user object dump {username}") {
  102. //Dump the given user object as json
  103. userinfo, err := userHandler.GetUserInfoFromUsername(chunk[3])
  104. if err != nil {
  105. return err.Error()
  106. }
  107. jsonString, _ := json.Marshal(userinfo)
  108. return string(jsonString)
  109. } else if matchSubfix(chunk, []string{"user", "quota"}, 3, "user quota {username}") {
  110. //List user quota of the given username
  111. userinfo, err := userHandler.GetUserInfoFromUsername(chunk[2])
  112. if err != nil {
  113. return err.Error()
  114. }
  115. fmt.Println(userinfo.StorageQuota.UsedStorageQuota, "/", userinfo.StorageQuota.TotalStorageQuota)
  116. return "OK"
  117. }
  118. } else if len(chunk) > 0 && chunk[0] == "storage" {
  119. if matchSubfix(chunk, []string{"storage", "list", "basepool"}, 3, "") {
  120. //Dump the base storage pool
  121. jsonString, _ := json.Marshal(userHandler.GetStoragePool())
  122. return string(jsonString)
  123. }
  124. } else if len(chunk) > 0 && chunk[0] == "scan" {
  125. if matchSubfix(chunk, []string{"scan", "all"}, 2, "") {
  126. //scan all nearby arozos units
  127. fmt.Println("Scanning (Should take around 10s)")
  128. hosts := MDNS.Scan(10, "")
  129. for _, host := range hosts {
  130. fmt.Println(host)
  131. }
  132. return "OK"
  133. } else if matchSubfix(chunk, []string{"scan", "aroz"}, 2, "") || matchSubfix(chunk, []string{"scan", "arozos"}, 2, "") {
  134. //scan all nearby arozos units
  135. fmt.Println("Scanning nearybe ArozOS Hosts (Should take around 10s)")
  136. hosts := MDNS.Scan(10, "arozos.com")
  137. for _, host := range hosts {
  138. fmt.Println(host)
  139. }
  140. return "OK"
  141. }
  142. } else if len(chunk) > 0 && chunk[0] == "find" {
  143. if matchSubfix(chunk, []string{"find", "module"}, 3, "list module {modulename}") {
  144. //Display all loaded modules
  145. for _, module := range moduleHandler.LoadedModule {
  146. if strings.ToLower(module.Name) == strings.ToLower(chunk[2]) {
  147. jsonString, _ := json.Marshal(module)
  148. return string(jsonString)
  149. }
  150. }
  151. return string("Module not found")
  152. } else if matchSubfix(chunk, []string{"find", "modules"}, 2, "") {
  153. //Display all loaded modules
  154. jsonString, _ := json.Marshal(moduleHandler.LoadedModule)
  155. return string(jsonString)
  156. } else if matchSubfix(chunk, []string{"find", "subservices"}, 2, "") {
  157. //Display all loaded subservices
  158. fmt.Println(ssRouter.RunningSubService)
  159. return "OK"
  160. }
  161. } else if len(chunk) > 0 && chunk[0] == "access" {
  162. //Handle emergency situation where the user is blocked by himself
  163. if matchSubfix(chunk, []string{"access", "whitelist", "disable"}, 3, "") {
  164. //Disable whitelist
  165. authAgent.WhitelistManager.SetWhitelistEnabled(false)
  166. return "Whitelist Disabled"
  167. } else if matchSubfix(chunk, []string{"access", "whitelist", "enable"}, 3, "") {
  168. //Enable whitelist
  169. authAgent.WhitelistManager.SetWhitelistEnabled(true)
  170. return "Whitelist Enabled"
  171. } else if matchSubfix(chunk, []string{"access", "whitelist", "add"}, 4, "access whitelist add {ip_range}") {
  172. err = authAgent.WhitelistManager.SetWhitelist(chunk[3])
  173. if err != nil {
  174. return err.Error()
  175. }
  176. return "OK"
  177. } else if matchSubfix(chunk, []string{"access", "whitelist", "del"}, 4, "access whitelist del {ip_range}") {
  178. err = authAgent.WhitelistManager.UnsetWhitelist(chunk[3])
  179. if err != nil {
  180. return err.Error()
  181. }
  182. return "OK"
  183. } else if matchSubfix(chunk, []string{"access", "blacklist", "enable"}, 3, "") {
  184. //Enable blacklist
  185. authAgent.WhitelistManager.SetWhitelistEnabled(true)
  186. return "Blacklist Enabled"
  187. } else if matchSubfix(chunk, []string{"access", "blacklist", "disable"}, 3, "") {
  188. //Disable blacklist
  189. authAgent.BlacklistManager.SetBlacklistEnabled(false)
  190. return "Blacklist Disabled"
  191. } else {
  192. return "[Whitelist / Blacklist Console Control API] \nUsage: access {whitelist/blacklist} {action} {data}"
  193. }
  194. } else if len(chunk) == 1 && chunk[0] == "stop" {
  195. //Stopping the server
  196. fmt.Println("Shutting down aroz online system by terminal request")
  197. executeShutdownSequence()
  198. }
  199. return "Invalid Command. Given: '" + strings.Join(chunk, " ") + "'"
  200. }
  201. // Check if the given line input match the requirement
  202. func matchSubfix(chunk []string, match []string, minlength int, usageExample string) bool {
  203. matching := true
  204. //Check if the chunk contains minmium length of the command request
  205. if len(chunk) >= len(match) {
  206. for i, cchunk := range match {
  207. if chunk[i] != cchunk {
  208. matching = false
  209. }
  210. }
  211. } else {
  212. matching = false
  213. }
  214. if len(chunk)-minlength == -1 && chunk[len(chunk)-1] == match[len(match)-1] {
  215. fmt.Println("Paramter missing. Usage: " + usageExample)
  216. return false
  217. }
  218. return matching
  219. }
  220. func parseCommandLine(command string) ([]string, error) {
  221. var args []string
  222. state := "start"
  223. current := ""
  224. quote := "\""
  225. escapeNext := true
  226. for i := 0; i < len(command); i++ {
  227. c := command[i]
  228. if state == "quotes" {
  229. if string(c) != quote {
  230. current += string(c)
  231. } else {
  232. args = append(args, current)
  233. current = ""
  234. state = "start"
  235. }
  236. continue
  237. }
  238. if escapeNext {
  239. current += string(c)
  240. escapeNext = false
  241. continue
  242. }
  243. if c == '\\' {
  244. escapeNext = true
  245. continue
  246. }
  247. if c == '"' || c == '\'' {
  248. state = "quotes"
  249. quote = string(c)
  250. continue
  251. }
  252. if state == "arg" {
  253. if c == ' ' || c == '\t' {
  254. args = append(args, current)
  255. current = ""
  256. state = "start"
  257. } else {
  258. current += string(c)
  259. }
  260. continue
  261. }
  262. if c != ' ' && c != '\t' {
  263. state = "arg"
  264. current += string(c)
  265. }
  266. }
  267. if state == "quotes" {
  268. return []string{}, errors.New(fmt.Sprintf("Unclosed quote in command line: %s", command))
  269. }
  270. if current != "" {
  271. args = append(args, current)
  272. }
  273. return args, nil
  274. }