Add: Server variables are opt-out by default
- Pull the Nushell and Deno versions from the server. - Support downloading Nushell and Deno from a url (not GitHUb). - Add support for nu config.nu and env.nu files. - Add support for default Deno permissions.
This commit is contained in:
		| @@ -89,12 +89,11 @@ const ( | |||||||
| 	nixMeshDir           = "/opt/tacticalmesh" | 	nixMeshDir           = "/opt/tacticalmesh" | ||||||
| 	nixAgentBin          = nixAgentDir + "/tacticalagent" | 	nixAgentBin          = nixAgentDir + "/tacticalagent" | ||||||
| 	nixAgentBinDir       = nixAgentDir + "/bin" | 	nixAgentBinDir       = nixAgentDir + "/bin" | ||||||
|  | 	nixAgentEtcDir       = nixAgentDir + "/etc" | ||||||
| 	nixMeshAgentBin      = nixMeshDir + "/meshagent" | 	nixMeshAgentBin      = nixMeshDir + "/meshagent" | ||||||
| 	macPlistPath         = "/Library/LaunchDaemons/tacticalagent.plist" | 	macPlistPath         = "/Library/LaunchDaemons/tacticalagent.plist" | ||||||
| 	macPlistName         = "tacticalagent" | 	macPlistName         = "tacticalagent" | ||||||
| 	defaultMacMeshSvcDir = "/usr/local/mesh_services" | 	defaultMacMeshSvcDir = "/usr/local/mesh_services" | ||||||
| 	nuVersion            = "0.87.0" |  | ||||||
| 	denoVersion          = "v1.38.2" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var defaultWinTmpDir = filepath.Join(os.Getenv("PROGRAMDATA"), "TacticalRMM") | var defaultWinTmpDir = filepath.Join(os.Getenv("PROGRAMDATA"), "TacticalRMM") | ||||||
|   | |||||||
| @@ -167,7 +167,7 @@ func NewAgentConfig() *rmm.AgentConfig { | |||||||
| 	return ret | 	return ret | ||||||
| } | } | ||||||
|  |  | ||||||
| func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string) (stdout, stderr string, exitcode int, e error) { | func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string, nushellEnableConfig bool, denoDefaultPermissions string) (stdout, stderr string, exitcode int, e error) { | ||||||
| 	code = removeWinNewLines(code) | 	code = removeWinNewLines(code) | ||||||
| 	content := []byte(code) | 	content := []byte(code) | ||||||
|  |  | ||||||
| @@ -197,12 +197,21 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, | |||||||
| 	opts.IsScript = true | 	opts.IsScript = true | ||||||
| 	switch shell { | 	switch shell { | ||||||
| 	case "nushell": | 	case "nushell": | ||||||
|  | 		var nushellArgs []string | ||||||
|  | 		if nushellEnableConfig { | ||||||
|  | 			nushellArgs = []string{ | ||||||
|  | 				"--config", | ||||||
|  | 				path.Join(nixAgentEtcDir, "nushell", "config.nu"), | ||||||
|  | 				"--env-config", | ||||||
|  | 				path.Join(nixAgentEtcDir, "nushell", "env.nu"), | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			nushellArgs = []string{"--no-config-file"} | ||||||
|  | 		} | ||||||
| 		opts.Shell = a.NuBin | 		opts.Shell = a.NuBin | ||||||
| 		opts.Args = append([]string{ | 		opts.Args = nushellArgs | ||||||
| 			"--no-config-file", | 		opts.Args = append(opts.Args, f.Name()) | ||||||
| 			f.Name(), | 		opts.Args = append(opts.Args, args...) | ||||||
| 		}, |  | ||||||
| 			args...) |  | ||||||
| 		if !trmm.FileExists(a.NuBin) { | 		if !trmm.FileExists(a.NuBin) { | ||||||
| 			a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin) | 			a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin) | ||||||
| 			err := errors.New("File Not Found: " + a.NuBin) | 			err := errors.New("File Not Found: " + a.NuBin) | ||||||
| @@ -225,6 +234,8 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, | |||||||
| 		// https://docs.deno.com/runtime/manual/basics/permissions#permissions-list | 		// https://docs.deno.com/runtime/manual/basics/permissions#permissions-list | ||||||
| 		// DENO_PERMISSIONS is not an official environment variable. | 		// DENO_PERMISSIONS is not an official environment variable. | ||||||
| 		// https://docs.deno.com/runtime/manual/basics/env_variables | 		// https://docs.deno.com/runtime/manual/basics/env_variables | ||||||
|  | 		// DENO_DEFAULT_PERMISSIONS is used if not found in the environment variables. | ||||||
|  | 		found := false | ||||||
| 		for i, v := range envVars { | 		for i, v := range envVars { | ||||||
| 			if strings.HasPrefix(v, "DENO_PERMISSIONS=") { | 			if strings.HasPrefix(v, "DENO_PERMISSIONS=") { | ||||||
| 				permissions := strings.Split(v, "=")[1] | 				permissions := strings.Split(v, "=")[1] | ||||||
| @@ -232,9 +243,13 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, | |||||||
| 				// Remove the DENO_PERMISSIONS variable from the environment variables slice. | 				// Remove the DENO_PERMISSIONS variable from the environment variables slice. | ||||||
| 				// It's possible more variables may exist with the same prefix. | 				// It's possible more variables may exist with the same prefix. | ||||||
| 				envVars = append(envVars[:i], envVars[i+1:]...) | 				envVars = append(envVars[:i], envVars[i+1:]...) | ||||||
|  | 				found = true | ||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		if !found && denoDefaultPermissions != "" { | ||||||
|  | 			opts.Args = append(opts.Args, strings.Split(denoDefaultPermissions, " ")...) | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		// Can't append a variadic slice after a string arg. | 		// Can't append a variadic slice after a string arg. | ||||||
| 		// https://pkg.go.dev/builtin#append | 		// https://pkg.go.dev/builtin#append | ||||||
| @@ -536,11 +551,321 @@ func (a *Agent) GetWMIInfo() map[string]interface{} { | |||||||
| 	return wmiInfo | 	return wmiInfo | ||||||
| } | } | ||||||
|  |  | ||||||
| // windows only below TODO add into stub file | // InstallNushell will download nushell from GitHub and install (copy) it to nixAgentBinDir | ||||||
|  | func (a *Agent) InstallNushell(force bool) { | ||||||
|  | 	conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) | ||||||
|  | 	if !conf.InstallNushell { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if trmm.FileExists(a.NuBin) { | ||||||
|  | 		if force { | ||||||
|  | 			a.Logger.Debugln(a.NuBin, "InstallNushell(): Forced install. Removing nu binary.") | ||||||
|  | 			err := os.Remove(a.NuBin) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error removing nu binary:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !trmm.FileExists(nixAgentBinDir) { | ||||||
|  | 		err := os.MkdirAll(nixAgentBinDir, 0755) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallNushell(): Error creating nixAgentBinDir:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if conf.NushellEnableConfig { | ||||||
|  | 		// Create 0-byte config files for Nushell | ||||||
|  | 		nushellPath := path.Join(nixAgentEtcDir, "nushell") | ||||||
|  | 		nushellConfig := path.Join(nushellPath, "config.nu") | ||||||
|  | 		nushellEnv := path.Join(nushellPath, "env.nu") | ||||||
|  | 		if !trmm.FileExists(nushellPath) { | ||||||
|  | 			err := os.MkdirAll(nushellPath, 0755) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error creating nixAgentEtcDir/nushell:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if !trmm.FileExists(nushellConfig) { | ||||||
|  | 			_, err := os.Create(nushellConfig) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error creating nushell config.nu:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			err = os.Chmod(nushellConfig, 0744) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell config.nu:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if !trmm.FileExists(nushellEnv) { | ||||||
|  | 			_, err := os.Create(nushellEnv) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error creating nushell env.nu:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			err = os.Chmod(nushellEnv, 0744) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell env.nu:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var ( | ||||||
|  | 		assetName    string | ||||||
|  | 		url          string | ||||||
|  | 		targzDirName string | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	if conf.InstallNushellUrl != "" { | ||||||
|  | 		url = conf.InstallNushellUrl | ||||||
|  | 		url = strings.Replace(url, "{OS}", runtime.GOOS, -1) | ||||||
|  | 		url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1) | ||||||
|  | 		url = strings.Replace(url, "{VERSION}", conf.InstallNushellVersion, -1) | ||||||
|  | 	} else { | ||||||
|  | 		switch runtime.GOOS { | ||||||
|  | 		case "darwin": | ||||||
|  | 			switch runtime.GOARCH { | ||||||
|  | 			case "arm64": | ||||||
|  | 				// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-darwin-full.tar.gz | ||||||
|  | 				assetName = fmt.Sprintf("nu-%s-aarch64-darwin-full.tar.gz", conf.InstallNushellVersion) | ||||||
|  | 			default: | ||||||
|  | 				a.Logger.Debugln("InstallNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		case "linux": | ||||||
|  | 			switch runtime.GOARCH { | ||||||
|  | 			case "amd64": | ||||||
|  | 				// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-linux-musl-full.tar.gz | ||||||
|  | 				assetName = fmt.Sprintf("nu-%s-x86_64-linux-musl-full.tar.gz", conf.InstallNushellVersion) | ||||||
|  | 			case "arm64": | ||||||
|  | 				// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-linux-gnu-full.tar.gz | ||||||
|  | 				assetName = fmt.Sprintf("nu-%s-aarch64-linux-gnu-full.tar.gz", conf.InstallNushellVersion) | ||||||
|  | 			default: | ||||||
|  | 				a.Logger.Debugln("InstallNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			a.Logger.Debugln("InstallNushell(): Unsupported OS:", runtime.GOOS) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", conf.InstallNushellVersion, assetName) | ||||||
|  | 	} | ||||||
|  | 	a.Logger.Debugln("InstallNushell(): Nu download url:", url) | ||||||
|  |  | ||||||
|  | 	tmpDir, err := os.MkdirTemp("", "trmm") | ||||||
|  | 	if err != nil { | ||||||
|  | 		a.Logger.Errorln("InstallNushell(): Error creating temp directory:", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	defer func(path string) { | ||||||
|  | 		err := os.RemoveAll(path) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallNushell(): Error removing temp directory:", err) | ||||||
|  | 		} | ||||||
|  | 	}(tmpDir) | ||||||
|  |  | ||||||
|  | 	tmpAssetName := filepath.Join(tmpDir, assetName) | ||||||
|  | 	a.Logger.Debugln("InstallNushell(): tmpAssetName:", tmpAssetName) | ||||||
|  |  | ||||||
|  | 	rClient := resty.New() | ||||||
|  | 	rClient.SetTimeout(20 * time.Minute) | ||||||
|  | 	rClient.SetRetryCount(10) | ||||||
|  | 	rClient.SetRetryWaitTime(1 * time.Minute) | ||||||
|  | 	rClient.SetRetryMaxWaitTime(15 * time.Minute) | ||||||
|  | 	if len(a.Proxy) > 0 { | ||||||
|  | 		rClient.SetProxy(a.Proxy) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r, err := rClient.R().SetOutput(tmpAssetName).Get(url) | ||||||
|  | 	if err != nil { | ||||||
|  | 		a.Logger.Errorln("InstallNushell(): Unable to download nu:", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if r.IsError() { | ||||||
|  | 		a.Logger.Errorln("InstallNushell(): Unable to download nu. Status code:", r.StatusCode()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if conf.InstallNushellUrl != "" { | ||||||
|  | 		// InstallNushellUrl is not compressed. | ||||||
|  | 		err = copyFile(path.Join(tmpDir, tmpAssetName), a.NuBin) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallNushell(): Failed to copy nu file to install dir:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// GitHub asset is tar.gz compressed. | ||||||
|  | 		targzDirName, err = a.ExtractTarGz(tmpAssetName, tmpDir) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallNushell(): Failed to extract downloaded tar.gz file:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		err = copyFile(path.Join(tmpDir, targzDirName, "nu"), a.NuBin) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallNushell(): Failed to copy nu file to install dir:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = os.Chmod(a.NuBin, 0755) | ||||||
|  | 	if err != nil { | ||||||
|  | 		a.Logger.Errorln("InstallNushell(): Failed to chmod nu binary:", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // InstallDeno will download deno from GitHub and install (copy) it to nixAgentBinDir | ||||||
|  | func (a *Agent) InstallDeno(force bool) { | ||||||
|  | 	conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) | ||||||
|  | 	if !conf.InstallDeno { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if trmm.FileExists(a.DenoBin) { | ||||||
|  | 		if force { | ||||||
|  | 			a.Logger.Debugln(a.NuBin, "InstallDeno(): Forced install. Removing deno binary.") | ||||||
|  | 			err := os.Remove(a.DenoBin) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallDeno(): Error removing deno binary:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !trmm.FileExists(nixAgentBinDir) { | ||||||
|  | 		err := os.MkdirAll(nixAgentBinDir, 0755) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallDeno(): Error creating nixAgentBinDir:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var ( | ||||||
|  | 		assetName string | ||||||
|  | 		url       string | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	if conf.InstallDenoUrl != "" { | ||||||
|  | 		url = conf.InstallDenoUrl | ||||||
|  | 		url = strings.Replace(url, "{OS}", runtime.GOOS, -1) | ||||||
|  | 		url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1) | ||||||
|  | 		url = strings.Replace(url, "{VERSION}", conf.InstallDenoVersion, -1) | ||||||
|  | 	} else { | ||||||
|  | 		switch runtime.GOOS { | ||||||
|  | 		case "darwin": | ||||||
|  | 			switch runtime.GOARCH { | ||||||
|  | 			case "arm64": | ||||||
|  | 				// https://github.com/denoland/deno/releases/download/v1.38.2/deno-aarch64-apple-darwin.zip | ||||||
|  | 				assetName = fmt.Sprintf("deno-aarch64-apple-darwin.zip") | ||||||
|  | 			case "amd64": | ||||||
|  | 				// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-apple-darwin.zip | ||||||
|  | 				assetName = fmt.Sprintf("deno-x86_64-apple-darwin.zip") | ||||||
|  | 			default: | ||||||
|  | 				a.Logger.Debugln("InstallDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		case "linux": | ||||||
|  | 			switch runtime.GOARCH { | ||||||
|  | 			case "amd64": | ||||||
|  | 				// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-unknown-linux-gnu.zip | ||||||
|  | 				assetName = fmt.Sprintf("deno-x86_64-unknown-linux-gnu.zip") | ||||||
|  | 			default: | ||||||
|  | 				a.Logger.Debugln("InstallDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			a.Logger.Debugln("InstallDeno(): Unsupported OS:", runtime.GOOS) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", conf.InstallDenoVersion, assetName) | ||||||
|  | 	} | ||||||
|  | 	a.Logger.Debugln("InstallDeno(): Deno download url:", url) | ||||||
|  |  | ||||||
|  | 	tmpDir, err := os.MkdirTemp("", "trmm") | ||||||
|  | 	if err != nil { | ||||||
|  | 		a.Logger.Errorln("InstallDeno(): Error creating temp directory:", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	defer func(path string) { | ||||||
|  | 		err := os.RemoveAll(path) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallDeno(): Error removing temp directory:", err) | ||||||
|  | 		} | ||||||
|  | 	}(tmpDir) | ||||||
|  |  | ||||||
|  | 	tmpAssetName := filepath.Join(tmpDir, assetName) | ||||||
|  | 	a.Logger.Debugln("InstallDeno(): tmpAssetName:", tmpAssetName) | ||||||
|  |  | ||||||
|  | 	rClient := resty.New() | ||||||
|  | 	rClient.SetTimeout(20 * time.Minute) | ||||||
|  | 	rClient.SetRetryCount(10) | ||||||
|  | 	rClient.SetRetryWaitTime(1 * time.Minute) | ||||||
|  | 	rClient.SetRetryMaxWaitTime(15 * time.Minute) | ||||||
|  | 	if len(a.Proxy) > 0 { | ||||||
|  | 		rClient.SetProxy(a.Proxy) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r, err := rClient.R().SetOutput(tmpAssetName).Get(url) | ||||||
|  | 	if err != nil { | ||||||
|  | 		a.Logger.Errorln("InstallDeno(): Unable to download deno:", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if r.IsError() { | ||||||
|  | 		a.Logger.Errorln("InstallDeno(): Unable to download deno. Status code:", r.StatusCode()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if conf.InstallDenoUrl != "" { | ||||||
|  | 		// InstallDenoUrl is not compressed. | ||||||
|  | 		err = copyFile(path.Join(tmpDir, tmpAssetName), a.DenoBin) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallDeno(): Failed to copy deno file to install dir:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// GitHub asset is zip compressed. | ||||||
|  | 		err = Unzip(tmpAssetName, tmpDir) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallDeno(): Failed to unzip downloaded zip file:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		err = copyFile(path.Join(tmpDir, "deno"), a.DenoBin) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallDeno(): Failed to copy deno file to install dir:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = os.Chmod(a.DenoBin, 0755) | ||||||
|  | 	if err != nil { | ||||||
|  | 		a.Logger.Errorln("InstallDeno(): Failed to chmod deno binary:", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetAgentCheckInConfig will get the agent configuration from the server. | ||||||
|  | // The Windows agent stores the configuration in the registry. The UNIX agent does not store the config. | ||||||
|  | // @return AgentCheckInConfig | ||||||
| func (a *Agent) GetAgentCheckInConfig(ret AgentCheckInConfig) AgentCheckInConfig { | func (a *Agent) GetAgentCheckInConfig(ret AgentCheckInConfig) AgentCheckInConfig { | ||||||
|  | 	// TODO: Persist the config to disk. | ||||||
| 	return ret | 	return ret | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // windows only below TODO add into stub file | ||||||
| func (a *Agent) PlatVer() (string, error) { return "", nil } | func (a *Agent) PlatVer() (string, error) { return "", nil } | ||||||
|  |  | ||||||
| func (a *Agent) SendSoftware() {} | func (a *Agent) SendSoftware() {} | ||||||
| @@ -553,235 +878,6 @@ func GetServiceStatus(name string) (string, error) { return "", nil } | |||||||
|  |  | ||||||
| func (a *Agent) GetPython(force bool) {} | func (a *Agent) GetPython(force bool) {} | ||||||
|  |  | ||||||
| // GetNushell will download nushell from GitHub and install (copy) it to nixAgentBinDir |  | ||||||
| func (a *Agent) GetNushell(force bool) { |  | ||||||
| 	if trmm.FileExists(a.NuBin) { |  | ||||||
| 		if force { |  | ||||||
| 			err := os.Remove(a.NuBin) |  | ||||||
| 			if err != nil { |  | ||||||
| 				a.Logger.Errorln("GetNushell(): Error removing nu binary:", err) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if !trmm.FileExists(nixAgentBinDir) { |  | ||||||
| 		err := os.MkdirAll(nixAgentBinDir, 0755) |  | ||||||
| 		if err != nil { |  | ||||||
| 			a.Logger.Errorln("GetNushell(): Error creating nixAgentBinDir:", err) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ( |  | ||||||
| 		assetName    string |  | ||||||
| 		url          string |  | ||||||
| 		targzDirName string |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	switch runtime.GOOS { |  | ||||||
| 	case "darwin": |  | ||||||
| 		switch runtime.GOARCH { |  | ||||||
| 		case "arm64": |  | ||||||
| 			// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-darwin-full.tar.gz |  | ||||||
| 			assetName = fmt.Sprintf("nu-%s-aarch64-darwin-full.tar.gz", nuVersion) |  | ||||||
| 		default: |  | ||||||
| 			a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	case "linux": |  | ||||||
| 		switch runtime.GOARCH { |  | ||||||
| 		case "amd64": |  | ||||||
| 			// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-linux-musl-full.tar.gz |  | ||||||
| 			assetName = fmt.Sprintf("nu-%s-x86_64-linux-musl-full.tar.gz", nuVersion) |  | ||||||
| 		case "arm64": |  | ||||||
| 			// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-linux-gnu-full.tar.gz |  | ||||||
| 			assetName = fmt.Sprintf("nu-%s-aarch64-linux-gnu-full.tar.gz", nuVersion) |  | ||||||
| 		default: |  | ||||||
| 			a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	default: |  | ||||||
| 		a.Logger.Debugln("GetNushell(): Unsupported OS:", runtime.GOOS) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", nuVersion, assetName) |  | ||||||
| 	a.Logger.Debugln("GetNushell(): Nu download url:", url) |  | ||||||
|  |  | ||||||
| 	tmpDir, err := os.MkdirTemp("", "trmm") |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetNushell(): Error creating temp directory:", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	defer func(path string) { |  | ||||||
| 		err := os.RemoveAll(path) |  | ||||||
| 		if err != nil { |  | ||||||
| 			a.Logger.Errorln("GetNushell(): Error removing temp directory:", err) |  | ||||||
| 		} |  | ||||||
| 	}(tmpDir) |  | ||||||
|  |  | ||||||
| 	tmpAssetName := filepath.Join(tmpDir, assetName) |  | ||||||
| 	a.Logger.Debugln("GetNushell(): tmpAssetName:", tmpAssetName) |  | ||||||
|  |  | ||||||
| 	rClient := resty.New() |  | ||||||
| 	rClient.SetTimeout(20 * time.Minute) |  | ||||||
| 	rClient.SetRetryCount(10) |  | ||||||
| 	rClient.SetRetryWaitTime(1 * time.Minute) |  | ||||||
| 	rClient.SetRetryMaxWaitTime(15 * time.Minute) |  | ||||||
| 	if len(a.Proxy) > 0 { |  | ||||||
| 		rClient.SetProxy(a.Proxy) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r, err := rClient.R().SetOutput(tmpAssetName).Get(url) |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetNushell(): Unable to download nu from github.", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if r.IsError() { |  | ||||||
| 		a.Logger.Errorln("GetNushell(): Unable to download nu from github. Status code", r.StatusCode()) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	targzDirName, err = a.ExtractTarGz(tmpAssetName, tmpDir) |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetNushell(): Failed to extract downloaded tar.gz file:", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = copyFile(path.Join(tmpDir, targzDirName, "nu"), a.NuBin) |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetNushell(): Failed to copy nu file to install dir:", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = os.Chmod(a.NuBin, 0755) |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetNushell(): Failed to chmod nu binary:", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // GetDeno will download deno from GitHub and install (copy) it to nixAgentBinDir |  | ||||||
| func (a *Agent) GetDeno(force bool) { |  | ||||||
| 	if trmm.FileExists(a.DenoBin) { |  | ||||||
| 		if force { |  | ||||||
| 			err := os.Remove(a.DenoBin) |  | ||||||
| 			if err != nil { |  | ||||||
| 				a.Logger.Errorln("GetDeno(): Error removing deno binary:", err) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if !trmm.FileExists(nixAgentBinDir) { |  | ||||||
| 		err := os.MkdirAll(nixAgentBinDir, 0755) |  | ||||||
| 		if err != nil { |  | ||||||
| 			a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ( |  | ||||||
| 		assetName string |  | ||||||
| 		url       string |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	switch runtime.GOOS { |  | ||||||
| 	case "darwin": |  | ||||||
| 		switch runtime.GOARCH { |  | ||||||
| 		case "arm64": |  | ||||||
| 			// https://github.com/denoland/deno/releases/download/v1.38.2/deno-aarch64-apple-darwin.zip |  | ||||||
| 			assetName = fmt.Sprintf("deno-aarch64-apple-darwin.zip") |  | ||||||
| 		case "amd64": |  | ||||||
| 			// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-apple-darwin.zip |  | ||||||
| 			assetName = fmt.Sprintf("deno-x86_64-apple-darwin.zip") |  | ||||||
| 		default: |  | ||||||
| 			a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	case "linux": |  | ||||||
| 		switch runtime.GOARCH { |  | ||||||
| 		case "amd64": |  | ||||||
| 			// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-unknown-linux-gnu.zip |  | ||||||
| 			assetName = fmt.Sprintf("deno-x86_64-unknown-linux-gnu.zip") |  | ||||||
| 		default: |  | ||||||
| 			a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	default: |  | ||||||
| 		a.Logger.Debugln("GetDeno(): Unsupported OS:", runtime.GOOS) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", denoVersion, assetName) |  | ||||||
| 	a.Logger.Debugln("GetDeno(): Deno download url:", url) |  | ||||||
|  |  | ||||||
| 	tmpDir, err := os.MkdirTemp("", "trmm") |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetDeno(): Error creating temp directory:", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	defer func(path string) { |  | ||||||
| 		err := os.RemoveAll(path) |  | ||||||
| 		if err != nil { |  | ||||||
| 			a.Logger.Errorln("GetDeno(): Error removing temp directory:", err) |  | ||||||
| 		} |  | ||||||
| 	}(tmpDir) |  | ||||||
|  |  | ||||||
| 	tmpAssetName := filepath.Join(tmpDir, assetName) |  | ||||||
| 	a.Logger.Debugln("GetDeno(): tmpAssetName:", tmpAssetName) |  | ||||||
|  |  | ||||||
| 	if !trmm.FileExists(nixAgentBinDir) { |  | ||||||
| 		err = os.MkdirAll(nixAgentBinDir, 0755) |  | ||||||
| 		if err != nil { |  | ||||||
| 			a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	rClient := resty.New() |  | ||||||
| 	rClient.SetTimeout(20 * time.Minute) |  | ||||||
| 	rClient.SetRetryCount(10) |  | ||||||
| 	rClient.SetRetryWaitTime(1 * time.Minute) |  | ||||||
| 	rClient.SetRetryMaxWaitTime(15 * time.Minute) |  | ||||||
| 	if len(a.Proxy) > 0 { |  | ||||||
| 		rClient.SetProxy(a.Proxy) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r, err := rClient.R().SetOutput(tmpAssetName).Get(url) |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetDeno(): Unable to download deno from github.", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if r.IsError() { |  | ||||||
| 		a.Logger.Errorln("GetDeno(): Unable to download deno from github. Status code", r.StatusCode()) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = Unzip(tmpAssetName, tmpDir) |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetDeno(): Failed to unzip downloaded zip file:", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = copyFile(path.Join(tmpDir, "deno"), a.DenoBin) |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetDeno(): Failed to copy deno file to install dir:", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = os.Chmod(a.DenoBin, 0755) |  | ||||||
| 	if err != nil { |  | ||||||
| 		a.Logger.Errorln("GetDeno(): Failed to chmod deno binary:", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SchedTask struct{ Name string } | type SchedTask struct{ Name string } | ||||||
|  |  | ||||||
| func (a *Agent) PatchMgmnt(enable bool) error { return nil } | func (a *Agent) PatchMgmnt(enable bool) error { return nil } | ||||||
|   | |||||||
| @@ -92,7 +92,7 @@ func NewAgentConfig() *rmm.AgentConfig { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string) (stdout, stderr string, exitcode int, e error) { | func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string, nushellEnableConfig bool, denoDefaultPermissions string) (stdout, stderr string, exitcode int, e error) { | ||||||
|  |  | ||||||
| 	content := []byte(code) | 	content := []byte(code) | ||||||
|  |  | ||||||
| @@ -158,7 +158,18 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, | |||||||
| 		exe = tmpfn.Name() | 		exe = tmpfn.Name() | ||||||
| 	case "nushell": | 	case "nushell": | ||||||
| 		exe = a.NuBin | 		exe = a.NuBin | ||||||
| 		cmdArgs = []string{"--no-config-file", tmpfn.Name()} | 		var nushellArgs []string | ||||||
|  | 		if nushellEnableConfig { | ||||||
|  | 			nushellArgs = []string{ | ||||||
|  | 				"--config", | ||||||
|  | 				path.Join(a.ProgramDir, "etc", "nushell", "config.nu"), | ||||||
|  | 				"--env-config", | ||||||
|  | 				path.Join(a.ProgramDir, "etc", "nushell", "env.nu"), | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			nushellArgs = []string{"--no-config-file"} | ||||||
|  | 		} | ||||||
|  | 		cmdArgs = append(nushellArgs, tmpfn.Name()) | ||||||
| 		if !trmm.FileExists(a.NuBin) { | 		if !trmm.FileExists(a.NuBin) { | ||||||
| 			a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin) | 			a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin) | ||||||
| 			err := errors.New("File Not Found: " + a.NuBin) | 			err := errors.New("File Not Found: " + a.NuBin) | ||||||
| @@ -177,6 +188,8 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, | |||||||
| 		// https://docs.deno.com/runtime/manual/basics/permissions#permissions-list | 		// https://docs.deno.com/runtime/manual/basics/permissions#permissions-list | ||||||
| 		// DENO_PERMISSIONS is not an official environment variable. | 		// DENO_PERMISSIONS is not an official environment variable. | ||||||
| 		// https://docs.deno.com/runtime/manual/basics/env_variables | 		// https://docs.deno.com/runtime/manual/basics/env_variables | ||||||
|  | 		// DENO_DEFAULT_PERMISSIONS is used if not found in the environment variables. | ||||||
|  | 		found := false | ||||||
| 		for i, v := range envVars { | 		for i, v := range envVars { | ||||||
| 			if strings.HasPrefix(v, "DENO_PERMISSIONS=") { | 			if strings.HasPrefix(v, "DENO_PERMISSIONS=") { | ||||||
| 				permissions := strings.Split(v, "=")[1] | 				permissions := strings.Split(v, "=")[1] | ||||||
| @@ -184,12 +197,13 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, | |||||||
| 				// Remove the DENO_PERMISSIONS variable from the environment variables slice. | 				// Remove the DENO_PERMISSIONS variable from the environment variables slice. | ||||||
| 				// It's possible more variables may exist with the same prefix. | 				// It's possible more variables may exist with the same prefix. | ||||||
| 				envVars = append(envVars[:i], envVars[i+1:]...) | 				envVars = append(envVars[:i], envVars[i+1:]...) | ||||||
|  | 				found = true | ||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		if !found && denoDefaultPermissions != "" { | ||||||
| 		// Can't append a variadic slice after a string arg. | 			cmdArgs = append(cmdArgs, strings.Split(denoDefaultPermissions, " ")...) | ||||||
| 		// https://pkg.go.dev/builtin#append | 		} | ||||||
| 		cmdArgs = append(cmdArgs, tmpfn.Name()) | 		cmdArgs = append(cmdArgs, tmpfn.Name()) | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
| @@ -879,14 +893,20 @@ func (a *Agent) GetPython(force bool) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // GetNushell will download nushell from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is | // InstallNushell will download nushell from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is | ||||||
| // initialized to C:\Program Files\TacticalAgent | // initialized to C:\Program Files\TacticalAgent | ||||||
| func (a *Agent) GetNushell(force bool) { | func (a *Agent) InstallNushell(force bool) { | ||||||
|  | 	conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) | ||||||
|  | 	if !conf.InstallNushell { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if trmm.FileExists(a.NuBin) { | 	if trmm.FileExists(a.NuBin) { | ||||||
| 		if force { | 		if force { | ||||||
|  | 			a.Logger.Debugln(a.NuBin, "InstallNushell(): Forced install. Removing nu.exe binary.") | ||||||
| 			err := os.Remove(a.NuBin) | 			err := os.Remove(a.NuBin) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				a.Logger.Errorln("GetNushell(): Error removing nu binary:", err) | 				a.Logger.Errorln("InstallNushell(): Error removing nu.exe binary:", err) | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| @@ -898,50 +918,96 @@ func (a *Agent) GetNushell(force bool) { | |||||||
| 	if !trmm.FileExists(programBinDir) { | 	if !trmm.FileExists(programBinDir) { | ||||||
| 		err := os.MkdirAll(programBinDir, 0755) | 		err := os.MkdirAll(programBinDir, 0755) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			a.Logger.Errorln("GetNushell(): Error creating Program Files bin folder:", err) | 			a.Logger.Errorln("InstallNushell(): Error creating Program Files bin folder:", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if conf.NushellEnableConfig { | ||||||
|  | 		// Create 0-byte config files for Nushell | ||||||
|  | 		nushellPath := path.Join(a.ProgramDir, "etc", "nushell") | ||||||
|  | 		nushellConfig := path.Join(nushellPath, "config.nu") | ||||||
|  | 		nushellEnv := path.Join(nushellPath, "env.nu") | ||||||
|  | 		if !trmm.FileExists(nushellPath) { | ||||||
|  | 			err := os.MkdirAll(nushellPath, 0755) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error creating Program Files/nushell:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if !trmm.FileExists(nushellConfig) { | ||||||
|  | 			_, err := os.Create(nushellConfig) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error creating nushell config.nu:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			err = os.Chmod(nushellConfig, 0744) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell config.nu:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if !trmm.FileExists(nushellEnv) { | ||||||
|  | 			_, err := os.Create(nushellEnv) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error creating nushell env.nu:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			err = os.Chmod(nushellEnv, 0744) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell env.nu:", err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		assetName string | 		assetName string | ||||||
| 		url       string | 		url       string | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	switch runtime.GOOS { | 	if conf.InstallNushellUrl != "" { | ||||||
| 	case "windows": | 		url = conf.InstallNushellUrl | ||||||
| 		switch runtime.GOARCH { | 		url = strings.Replace(url, "{OS}", runtime.GOOS, -1) | ||||||
| 		case "amd64": | 		url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1) | ||||||
| 			// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-windows-msvc-full.zip | 		url = strings.Replace(url, "{VERSION}", conf.InstallNushellVersion, -1) | ||||||
| 			assetName = fmt.Sprintf("nu-%s-x86_64-windows-msvc-full.zip", nuVersion) | 	} else { | ||||||
| 		case "arm64": | 		switch runtime.GOOS { | ||||||
| 			// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-windows-msvc-full.zip | 		case "windows": | ||||||
| 			assetName = fmt.Sprintf("nu-%s-aarch64-windows-msvc-full.zip", nuVersion) | 			switch runtime.GOARCH { | ||||||
|  | 			case "amd64": | ||||||
|  | 				// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-windows-msvc-full.zip | ||||||
|  | 				assetName = fmt.Sprintf("nu-%s-x86_64-windows-msvc-full.zip", conf.InstallNushellVersion) | ||||||
|  | 			case "arm64": | ||||||
|  | 				// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-windows-msvc-full.zip | ||||||
|  | 				assetName = fmt.Sprintf("nu-%s-aarch64-windows-msvc-full.zip", conf.InstallNushellVersion) | ||||||
|  | 			default: | ||||||
|  | 				a.Logger.Debugln("InstallNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
| 		default: | 		default: | ||||||
| 			a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) | 			a.Logger.Debugln("InstallNushell(): Unsupported OS:", runtime.GOOS) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	default: | 		url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", conf.InstallNushellVersion, assetName) | ||||||
| 		a.Logger.Debugln("GetNushell(): Unsupported OS:", runtime.GOOS) |  | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
| 	url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", nuVersion, assetName) | 	a.Logger.Debugln("InstallNushell(): Nu download url:", url) | ||||||
| 	a.Logger.Debugln("GetNushell(): Nu download url:", url) |  | ||||||
|  |  | ||||||
| 	tmpDir, err := os.MkdirTemp("", "trmm") | 	tmpDir, err := os.MkdirTemp("", "trmm") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		a.Logger.Errorln("GetNushell(): Error creating temp directory:", err) | 		a.Logger.Errorln("InstallNushell(): Error creating temp directory:", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	defer func(path string) { | 	defer func(path string) { | ||||||
| 		err := os.RemoveAll(path) | 		err := os.RemoveAll(path) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			a.Logger.Errorln("GetNushell(): Error removing temp directory:", err) | 			a.Logger.Errorln("InstallNushell(): Error removing temp directory:", err) | ||||||
| 		} | 		} | ||||||
| 	}(tmpDir) | 	}(tmpDir) | ||||||
|  |  | ||||||
| 	tmpAssetName := filepath.Join(tmpDir, assetName) | 	tmpAssetName := filepath.Join(tmpDir, assetName) | ||||||
| 	a.Logger.Debugln("GetNushell(): tmpAssetName:", tmpAssetName) | 	a.Logger.Debugln("InstallNushell(): tmpAssetName:", tmpAssetName) | ||||||
|  |  | ||||||
| 	rClient := resty.New() | 	rClient := resty.New() | ||||||
| 	rClient.SetTimeout(20 * time.Minute) | 	rClient.SetTimeout(20 * time.Minute) | ||||||
| @@ -954,35 +1020,50 @@ func (a *Agent) GetNushell(force bool) { | |||||||
|  |  | ||||||
| 	r, err := rClient.R().SetOutput(tmpAssetName).Get(url) | 	r, err := rClient.R().SetOutput(tmpAssetName).Get(url) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		a.Logger.Errorln("GetNushell(): Unable to download nu from github.", err) | 		a.Logger.Errorln("InstallNushell(): Unable to download nu:", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if r.IsError() { | 	if r.IsError() { | ||||||
| 		a.Logger.Errorln("GetNushell(): Unable to download nu from github. Status code", r.StatusCode()) | 		a.Logger.Errorln("InstallNushell(): Unable to download nu. Status code:", r.StatusCode()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = Unzip(tmpAssetName, tmpDir) | 	if conf.InstallNushellUrl != "" { | ||||||
| 	if err != nil { | 		// InstallNushellUrl is not compressed. | ||||||
| 		a.Logger.Errorln("GetNushell(): Failed to unzip downloaded zip file:", err) | 		err = copyFile(path.Join(tmpDir, tmpAssetName), a.NuBin) | ||||||
| 		return | 		if err != nil { | ||||||
| 	} | 			a.Logger.Errorln("InstallNushell(): Failed to copy nu file to install dir:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		err = Unzip(tmpAssetName, tmpDir) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallNushell(): Failed to unzip downloaded zip file:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 	err = copyFile(path.Join(tmpDir, "nu.exe"), a.NuBin) | 		err = copyFile(path.Join(tmpDir, "nu.exe"), a.NuBin) | ||||||
| 	if err != nil { | 		if err != nil { | ||||||
| 		a.Logger.Errorln("GetNushell(): Failed to copy nu.exe file to install dir:", err) | 			a.Logger.Errorln("InstallNushell(): Failed to copy nu.exe file to install dir:", err) | ||||||
| 		return | 			return | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // GetDeno will download deno from GitHub and install (copy) it to nixAgentBinDir | // InstallDeno will download deno from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is | ||||||
| func (a *Agent) GetDeno(force bool) { | // initialized to C:\Program Files\TacticalAgent | ||||||
|  | func (a *Agent) InstallDeno(force bool) { | ||||||
|  | 	conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) | ||||||
|  | 	if !conf.InstallDeno { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if trmm.FileExists(a.DenoBin) { | 	if trmm.FileExists(a.DenoBin) { | ||||||
| 		if force { | 		if force { | ||||||
| 			err := os.Remove(a.DenoBin) | 			err := os.Remove(a.DenoBin) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				a.Logger.Errorln("GetDeno(): Error removing deno binary:", err) | 				a.Logger.Errorln("InstallDeno(): Error removing deno binary:", err) | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| @@ -994,7 +1075,7 @@ func (a *Agent) GetDeno(force bool) { | |||||||
| 	if !trmm.FileExists(programBinDir) { | 	if !trmm.FileExists(programBinDir) { | ||||||
| 		err := os.MkdirAll(programBinDir, 0755) | 		err := os.MkdirAll(programBinDir, 0755) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			a.Logger.Errorln("GetDeno(): Error creating Program Files bin folder:", err) | 			a.Logger.Errorln("InstallDeno(): Error creating Program Files bin folder:", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -1004,45 +1085,44 @@ func (a *Agent) GetDeno(force bool) { | |||||||
| 		url       string | 		url       string | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	switch runtime.GOOS { | 	if conf.InstallDenoUrl != "" { | ||||||
| 	case "windows": | 		url = conf.InstallDenoUrl | ||||||
| 		switch runtime.GOARCH { | 		url = strings.Replace(url, "{OS}", runtime.GOOS, -1) | ||||||
| 		case "amd64": | 		url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1) | ||||||
| 			// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-pc-windows-msvc.zip | 		url = strings.Replace(url, "{VERSION}", conf.InstallDenoVersion, -1) | ||||||
| 			assetName = fmt.Sprintf("deno-x86_64-pc-windows-msvc.zip") | 	} else { | ||||||
|  | 		switch runtime.GOOS { | ||||||
|  | 		case "windows": | ||||||
|  | 			switch runtime.GOARCH { | ||||||
|  | 			case "amd64": | ||||||
|  | 				// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-pc-windows-msvc.zip | ||||||
|  | 				assetName = fmt.Sprintf("deno-x86_64-pc-windows-msvc.zip") | ||||||
|  | 			default: | ||||||
|  | 				a.Logger.Debugln("InstallDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
| 		default: | 		default: | ||||||
| 			a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) | 			a.Logger.Debugln("InstallDeno(): Unsupported OS:", runtime.GOOS) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	default: | 		url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", conf.InstallDenoVersion, assetName) | ||||||
| 		a.Logger.Debugln("GetDeno(): Unsupported OS:", runtime.GOOS) |  | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
| 	url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", denoVersion, assetName) | 	a.Logger.Debugln("InstallDeno(): Deno download url:", url) | ||||||
| 	a.Logger.Debugln("GetDeno(): Deno download url:", url) |  | ||||||
|  |  | ||||||
| 	tmpDir, err := os.MkdirTemp("", "trmm") | 	tmpDir, err := os.MkdirTemp("", "trmm") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		a.Logger.Errorln("GetDeno(): Error creating temp directory:", err) | 		a.Logger.Errorln("InstallDeno(): Error creating temp directory:", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	defer func(path string) { | 	defer func(path string) { | ||||||
| 		err := os.RemoveAll(path) | 		err := os.RemoveAll(path) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			a.Logger.Errorln("GetDeno(): Error removing temp directory:", err) | 			a.Logger.Errorln("InstallDeno(): Error removing temp directory:", err) | ||||||
| 		} | 		} | ||||||
| 	}(tmpDir) | 	}(tmpDir) | ||||||
|  |  | ||||||
| 	tmpAssetName := filepath.Join(tmpDir, assetName) | 	tmpAssetName := filepath.Join(tmpDir, assetName) | ||||||
| 	a.Logger.Debugln("GetDeno(): tmpAssetName:", tmpAssetName) | 	a.Logger.Debugln("InstallDeno(): tmpAssetName:", tmpAssetName) | ||||||
|  |  | ||||||
| 	if !trmm.FileExists(nixAgentBinDir) { |  | ||||||
| 		err = os.MkdirAll(nixAgentBinDir, 0755) |  | ||||||
| 		if err != nil { |  | ||||||
| 			a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	rClient := resty.New() | 	rClient := resty.New() | ||||||
| 	rClient.SetTimeout(20 * time.Minute) | 	rClient.SetTimeout(20 * time.Minute) | ||||||
| @@ -1055,24 +1135,34 @@ func (a *Agent) GetDeno(force bool) { | |||||||
|  |  | ||||||
| 	r, err := rClient.R().SetOutput(tmpAssetName).Get(url) | 	r, err := rClient.R().SetOutput(tmpAssetName).Get(url) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		a.Logger.Errorln("GetDeno(): Unable to download deno from github.", err) | 		a.Logger.Errorln("InstallDeno(): Unable to download deno:", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if r.IsError() { | 	if r.IsError() { | ||||||
| 		a.Logger.Errorln("GetDeno(): Unable to download deno from github. Status code", r.StatusCode()) | 		a.Logger.Errorln("InstallDeno(): Unable to download deno. Status code:", r.StatusCode()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = Unzip(tmpAssetName, tmpDir) | 	if conf.InstallDenoUrl != "" { | ||||||
| 	if err != nil { | 		// InstallDenoUrl is not compressed. | ||||||
| 		a.Logger.Errorln("GetDeno(): Failed to unzip downloaded zip file:", err) | 		err = copyFile(path.Join(tmpDir, tmpAssetName), a.DenoBin) | ||||||
| 		return | 		if err != nil { | ||||||
| 	} | 			a.Logger.Errorln("InstallDeno(): Failed to copy deno file to install dir:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// GitHub asset is zip compressed. | ||||||
|  | 		err = Unzip(tmpAssetName, tmpDir) | ||||||
|  | 		if err != nil { | ||||||
|  | 			a.Logger.Errorln("InstallDeno(): Failed to unzip downloaded zip file:", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 	err = copyFile(path.Join(tmpDir, "deno.exe"), a.DenoBin) | 		err = copyFile(path.Join(tmpDir, "deno.exe"), a.DenoBin) | ||||||
| 	if err != nil { | 		if err != nil { | ||||||
| 		a.Logger.Errorln("GetDeno(): Failed to copy deno.exe file to install dir:", err) | 			a.Logger.Errorln("InstallDeno(): Failed to copy deno.exe file to install dir:", err) | ||||||
| 		return | 			return | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -169,7 +169,7 @@ type ScriptCheckResult struct { | |||||||
| // ScriptCheck runs either bat, powershell or python script | // ScriptCheck runs either bat, powershell or python script | ||||||
| func (a *Agent) ScriptCheck(data rmm.Check, r *resty.Client) { | func (a *Agent) ScriptCheck(data rmm.Check, r *resty.Client) { | ||||||
| 	start := time.Now() | 	start := time.Now() | ||||||
| 	stdout, stderr, retcode, _ := a.RunScript(data.Script.Code, data.Script.Shell, data.ScriptArgs, data.Timeout, data.Script.RunAsUser, data.EnvVars) | 	stdout, stderr, retcode, _ := a.RunScript(data.Script.Code, data.Script.Shell, data.ScriptArgs, data.Timeout, data.Script.RunAsUser, data.EnvVars, data.NushellEnableConfig, data.DenoDefaultPermissions) | ||||||
|  |  | ||||||
| 	payload := ScriptCheckResult{ | 	payload := ScriptCheckResult{ | ||||||
| 		ID:      data.CheckPK, | 		ID:      data.CheckPK, | ||||||
|   | |||||||
| @@ -45,7 +45,7 @@ func (a *Agent) InstallChoco() { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	_, _, exitcode, err := a.RunScript(string(r.Body()), "powershell", []string{}, 900, false, []string{}) | 	_, _, exitcode, err := a.RunScript(string(r.Body()), "powershell", []string{}, 900, false, []string{}, false, "") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		a.Logger.Debugln(err) | 		a.Logger.Debugln(err) | ||||||
| 		a.rClient.R().SetBody(result).Post(url) | 		a.rClient.R().SetBody(result).Post(url) | ||||||
|   | |||||||
| @@ -20,5 +20,5 @@ import _ "embed" | |||||||
| var ventura_mesh_fix string | var ventura_mesh_fix string | ||||||
|  |  | ||||||
| func (a *Agent) FixVenturaMesh() { | func (a *Agent) FixVenturaMesh() { | ||||||
| 	a.RunScript(ventura_mesh_fix, "foo", []string{}, 45, false, []string{}) | 	a.RunScript(ventura_mesh_fix, "foo", []string{}, 45, false, []string{}, false, "") | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								agent/rpc.go
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								agent/rpc.go
									
									
									
									
									
								
							| @@ -26,22 +26,24 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| type NatsMsg struct { | type NatsMsg struct { | ||||||
| 	Func            string            `json:"func"` | 	Func                   string            `json:"func"` | ||||||
| 	Timeout         int               `json:"timeout"` | 	Timeout                int               `json:"timeout"` | ||||||
| 	Data            map[string]string `json:"payload"` | 	Data                   map[string]string `json:"payload"` | ||||||
| 	ScriptArgs      []string          `json:"script_args"` | 	ScriptArgs             []string          `json:"script_args"` | ||||||
| 	ProcPID         int32             `json:"procpid"` | 	ProcPID                int32             `json:"procpid"` | ||||||
| 	TaskPK          int               `json:"taskpk"` | 	TaskPK                 int               `json:"taskpk"` | ||||||
| 	ScheduledTask   SchedTask         `json:"schedtaskpayload"` | 	ScheduledTask          SchedTask         `json:"schedtaskpayload"` | ||||||
| 	RecoveryCommand string            `json:"recoverycommand"` | 	RecoveryCommand        string            `json:"recoverycommand"` | ||||||
| 	UpdateGUIDs     []string          `json:"guids"` | 	UpdateGUIDs            []string          `json:"guids"` | ||||||
| 	ChocoProgName   string            `json:"choco_prog_name"` | 	ChocoProgName          string            `json:"choco_prog_name"` | ||||||
| 	PendingActionPK int               `json:"pending_action_pk"` | 	PendingActionPK        int               `json:"pending_action_pk"` | ||||||
| 	PatchMgmt       bool              `json:"patch_mgmt"` | 	PatchMgmt              bool              `json:"patch_mgmt"` | ||||||
| 	ID              int               `json:"id"` | 	ID                     int               `json:"id"` | ||||||
| 	Code            string            `json:"code"` | 	Code                   string            `json:"code"` | ||||||
| 	RunAsUser       bool              `json:"run_as_user"` | 	RunAsUser              bool              `json:"run_as_user"` | ||||||
| 	EnvVars         []string          `json:"env_vars"` | 	EnvVars                []string          `json:"env_vars"` | ||||||
|  | 	NushellEnableConfig    bool              `json:"nushell_enable_config"` | ||||||
|  | 	DenoDefaultPermissions string            `json:"deno_default_permissions"` | ||||||
| } | } | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| @@ -264,7 +266,7 @@ func (a *Agent) RunRPC() { | |||||||
| 				var resultData rmm.RunScriptResp | 				var resultData rmm.RunScriptResp | ||||||
| 				ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle)) | 				ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle)) | ||||||
| 				start := time.Now() | 				start := time.Now() | ||||||
| 				stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars) | 				stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars, p.NushellEnableConfig, p.DenoDefaultPermissions) | ||||||
| 				resultData.ExecTime = time.Since(start).Seconds() | 				resultData.ExecTime = time.Since(start).Seconds() | ||||||
| 				resultData.ID = p.ID | 				resultData.ID = p.ID | ||||||
|  |  | ||||||
| @@ -294,7 +296,7 @@ func (a *Agent) RunRPC() { | |||||||
| 				var retData rmm.RunScriptResp | 				var retData rmm.RunScriptResp | ||||||
| 				ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle)) | 				ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle)) | ||||||
| 				start := time.Now() | 				start := time.Now() | ||||||
| 				stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars) | 				stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars, p.NushellEnableConfig, p.DenoDefaultPermissions) | ||||||
|  |  | ||||||
| 				retData.ExecTime = time.Since(start).Seconds() | 				retData.ExecTime = time.Since(start).Seconds() | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| @@ -438,9 +440,9 @@ func (a *Agent) RunRPC() { | |||||||
| 		case "installpython": | 		case "installpython": | ||||||
| 			go a.GetPython(true) | 			go a.GetPython(true) | ||||||
| 		case "installnushell": | 		case "installnushell": | ||||||
| 			go a.GetNushell(true) | 			go a.InstallNushell(true) | ||||||
| 		case "installdeno": | 		case "installdeno": | ||||||
| 			go a.GetDeno(true) | 			go a.InstallDeno(true) | ||||||
| 		case "installchoco": | 		case "installchoco": | ||||||
| 			go a.InstallChoco() | 			go a.InstallChoco() | ||||||
| 		case "installwithchoco": | 		case "installwithchoco": | ||||||
|   | |||||||
							
								
								
									
										56
									
								
								agent/svc.go
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								agent/svc.go
									
									
									
									
									
								
							| @@ -29,15 +29,23 @@ func (a *Agent) RunAsService(nc *nats.Conn) { | |||||||
| } | } | ||||||
|  |  | ||||||
| type AgentCheckInConfig struct { | type AgentCheckInConfig struct { | ||||||
| 	Hello     int  `json:"checkin_hello"` | 	Hello                  int    `json:"checkin_hello"` | ||||||
| 	AgentInfo int  `json:"checkin_agentinfo"` | 	AgentInfo              int    `json:"checkin_agentinfo"` | ||||||
| 	WinSvc    int  `json:"checkin_winsvc"` | 	WinSvc                 int    `json:"checkin_winsvc"` | ||||||
| 	PubIP     int  `json:"checkin_pubip"` | 	PubIP                  int    `json:"checkin_pubip"` | ||||||
| 	Disks     int  `json:"checkin_disks"` | 	Disks                  int    `json:"checkin_disks"` | ||||||
| 	SW        int  `json:"checkin_sw"` | 	SW                     int    `json:"checkin_sw"` | ||||||
| 	WMI       int  `json:"checkin_wmi"` | 	WMI                    int    `json:"checkin_wmi"` | ||||||
| 	SyncMesh  int  `json:"checkin_syncmesh"` | 	SyncMesh               int    `json:"checkin_syncmesh"` | ||||||
| 	LimitData bool `json:"limit_data"` | 	LimitData              bool   `json:"limit_data"` | ||||||
|  | 	InstallNushell         bool   `json:"install_nushell"` | ||||||
|  | 	InstallNushellVersion  string `json:"install_nushell_version"` | ||||||
|  | 	InstallNushellUrl      string `json:"install_nushell_url"` | ||||||
|  | 	NushellEnableConfig    bool   `json:"nushell_enable_config"` | ||||||
|  | 	InstallDeno            bool   `json:"install_deno"` | ||||||
|  | 	InstallDenoVersion     string `json:"install_deno_version"` | ||||||
|  | 	InstallDenoUrl         string `json:"install_deno_url"` | ||||||
|  | 	DenoDefaultPermissions string `json:"deno_default_permissions"` | ||||||
| } | } | ||||||
|  |  | ||||||
| func (a *Agent) AgentSvc(nc *nats.Conn) { | func (a *Agent) AgentSvc(nc *nats.Conn) { | ||||||
| @@ -49,8 +57,6 @@ func (a *Agent) AgentSvc(nc *nats.Conn) { | |||||||
| 			a.Logger.Errorln("AgentSvc() createWinTempDir():", err) | 			a.Logger.Errorln("AgentSvc() createWinTempDir():", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	a.GetNushell(false) |  | ||||||
| 	a.GetDeno(false) |  | ||||||
|  |  | ||||||
| 	a.RunMigrations() | 	a.RunMigrations() | ||||||
|  |  | ||||||
| @@ -64,8 +70,9 @@ func (a *Agent) AgentSvc(nc *nats.Conn) { | |||||||
| 		a.CleanupAgentUpdates() | 		a.CleanupAgentUpdates() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// Windows has GetAgentCheckInConfig() while unix has a stub GetAgentCheckInConfig() | ||||||
| 	conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) | 	conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) | ||||||
| 	a.Logger.Debugf("+%v\n", conf) | 	a.Logger.Debugf("AgentCheckInConf: %+v\n", conf) | ||||||
| 	for _, s := range natsCheckin { | 	for _, s := range natsCheckin { | ||||||
| 		if conf.LimitData && stringInSlice(s, limitNatsData) { | 		if conf.LimitData && stringInSlice(s, limitNatsData) { | ||||||
| 			continue | 			continue | ||||||
| @@ -75,6 +82,15 @@ func (a *Agent) AgentSvc(nc *nats.Conn) { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// The server conf check is also done in the functions to keep the parameters the same. | ||||||
|  | 	// Don't force a download when restarting the service. | ||||||
|  | 	if conf.InstallNushell { | ||||||
|  | 		a.InstallNushell(false) | ||||||
|  | 	} | ||||||
|  | 	if conf.InstallDeno { | ||||||
|  | 		a.InstallDeno(false) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	go a.SyncMeshNodeID() | 	go a.SyncMeshNodeID() | ||||||
|  |  | ||||||
| 	time.Sleep(time.Duration(randRange(1, 3)) * time.Second) | 	time.Sleep(time.Duration(randRange(1, 3)) * time.Second) | ||||||
| @@ -142,6 +158,14 @@ func (a *Agent) GetCheckInConfFromAPI() AgentCheckInConfig { | |||||||
| 		ret.WMI = randRange(3000, 4000) | 		ret.WMI = randRange(3000, 4000) | ||||||
| 		ret.SyncMesh = randRange(800, 1200) | 		ret.SyncMesh = randRange(800, 1200) | ||||||
| 		ret.LimitData = false | 		ret.LimitData = false | ||||||
|  | 		ret.InstallNushell = false | ||||||
|  | 		ret.InstallNushellVersion = "" | ||||||
|  | 		ret.InstallNushellUrl = "" | ||||||
|  | 		ret.NushellEnableConfig = false | ||||||
|  | 		ret.InstallDeno = false | ||||||
|  | 		ret.InstallDenoVersion = "" | ||||||
|  | 		ret.InstallDenoUrl = "" | ||||||
|  | 		ret.DenoDefaultPermissions = "" | ||||||
| 	} else { | 	} else { | ||||||
| 		ret.Hello = r.Result().(*AgentCheckInConfig).Hello | 		ret.Hello = r.Result().(*AgentCheckInConfig).Hello | ||||||
| 		ret.AgentInfo = r.Result().(*AgentCheckInConfig).AgentInfo | 		ret.AgentInfo = r.Result().(*AgentCheckInConfig).AgentInfo | ||||||
| @@ -152,6 +176,14 @@ func (a *Agent) GetCheckInConfFromAPI() AgentCheckInConfig { | |||||||
| 		ret.WMI = r.Result().(*AgentCheckInConfig).WMI | 		ret.WMI = r.Result().(*AgentCheckInConfig).WMI | ||||||
| 		ret.SyncMesh = r.Result().(*AgentCheckInConfig).SyncMesh | 		ret.SyncMesh = r.Result().(*AgentCheckInConfig).SyncMesh | ||||||
| 		ret.LimitData = r.Result().(*AgentCheckInConfig).LimitData | 		ret.LimitData = r.Result().(*AgentCheckInConfig).LimitData | ||||||
|  | 		ret.InstallNushell = r.Result().(*AgentCheckInConfig).InstallNushell | ||||||
|  | 		ret.InstallNushellVersion = r.Result().(*AgentCheckInConfig).InstallNushellVersion | ||||||
|  | 		ret.InstallNushellUrl = r.Result().(*AgentCheckInConfig).InstallNushellUrl | ||||||
|  | 		ret.NushellEnableConfig = r.Result().(*AgentCheckInConfig).NushellEnableConfig | ||||||
|  | 		ret.InstallDeno = r.Result().(*AgentCheckInConfig).InstallDeno | ||||||
|  | 		ret.InstallDenoVersion = r.Result().(*AgentCheckInConfig).InstallDenoVersion | ||||||
|  | 		ret.InstallDenoUrl = r.Result().(*AgentCheckInConfig).InstallDenoUrl | ||||||
|  | 		ret.DenoDefaultPermissions = r.Result().(*AgentCheckInConfig).DenoDefaultPermissions | ||||||
| 	} | 	} | ||||||
| 	return ret | 	return ret | ||||||
| } | } | ||||||
|   | |||||||
| @@ -14,13 +14,13 @@ package agent | |||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"github.com/amidaware/taskmaster" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	rmm "github.com/amidaware/rmmagent/shared" | 	rmm "github.com/amidaware/rmmagent/shared" | ||||||
| 	"github.com/amidaware/taskmaster" |  | ||||||
| 	"github.com/rickb777/date/period" | 	"github.com/rickb777/date/period" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -59,7 +59,7 @@ func (a *Agent) RunTask(id int) error { | |||||||
|  |  | ||||||
| 		action_start := time.Now() | 		action_start := time.Now() | ||||||
| 		if action.ActionType == "script" { | 		if action.ActionType == "script" { | ||||||
| 			stdout, stderr, retcode, err := a.RunScript(action.Code, action.Shell, action.Args, action.Timeout, action.RunAsUser, action.EnvVars) | 			stdout, stderr, retcode, err := a.RunScript(action.Code, action.Shell, action.Args, action.Timeout, action.RunAsUser, action.EnvVars, action.NushellEnableConfig, action.DenoDefaultPermissions) | ||||||
|  |  | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				a.Logger.Debugln(err) | 				a.Logger.Debugln(err) | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								main.go
									
									
									
									
									
								
							| @@ -117,10 +117,10 @@ func main() { | |||||||
| 		fmt.Println(a.PublicIP()) | 		fmt.Println(a.PublicIP()) | ||||||
| 	case "getpython": | 	case "getpython": | ||||||
| 		a.GetPython(true) | 		a.GetPython(true) | ||||||
| 	case "getdeno": | 	case "installdeno": | ||||||
| 		a.GetDeno(true) | 		a.InstallDeno(true) | ||||||
| 	case "getnushell": | 	case "installnushell": | ||||||
| 		a.GetNushell(true) | 		a.InstallNushell(true) | ||||||
| 	case "runmigrations": | 	case "runmigrations": | ||||||
| 		a.RunMigrations() | 		a.RunMigrations() | ||||||
| 	case "recovermesh": | 	case "recovermesh": | ||||||
|   | |||||||
| @@ -157,29 +157,31 @@ type CheckInfo struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| type Check struct { | type Check struct { | ||||||
| 	Script           Script         `json:"script"` | 	Script                 Script         `json:"script"` | ||||||
| 	AssignedTasks    []AssignedTask `json:"assigned_tasks"` | 	AssignedTasks          []AssignedTask `json:"assigned_tasks"` | ||||||
| 	CheckPK          int            `json:"id"` | 	CheckPK                int            `json:"id"` | ||||||
| 	CheckType        string         `json:"check_type"` | 	CheckType              string         `json:"check_type"` | ||||||
| 	Status           string         `json:"status"` | 	Status                 string         `json:"status"` | ||||||
| 	Threshold        int            `json:"threshold"` | 	Threshold              int            `json:"threshold"` | ||||||
| 	Disk             string         `json:"disk"` | 	Disk                   string         `json:"disk"` | ||||||
| 	IP               string         `json:"ip"` | 	IP                     string         `json:"ip"` | ||||||
| 	ScriptArgs       []string       `json:"script_args"` | 	ScriptArgs             []string       `json:"script_args"` | ||||||
| 	EnvVars          []string       `json:"env_vars"` | 	EnvVars                []string       `json:"env_vars"` | ||||||
| 	Timeout          int            `json:"timeout"` | 	NushellEnableConfig    bool           `json:"nushell_enable_config"` | ||||||
| 	ServiceName      string         `json:"svc_name"` | 	DenoDefaultPermissions string         `json:"deno_default_permissions"` | ||||||
| 	PassStartPending bool           `json:"pass_if_start_pending"` | 	Timeout                int            `json:"timeout"` | ||||||
| 	PassNotExist     bool           `json:"pass_if_svc_not_exist"` | 	ServiceName            string         `json:"svc_name"` | ||||||
| 	RestartIfStopped bool           `json:"restart_if_stopped"` | 	PassStartPending       bool           `json:"pass_if_start_pending"` | ||||||
| 	LogName          string         `json:"log_name"` | 	PassNotExist           bool           `json:"pass_if_svc_not_exist"` | ||||||
| 	EventID          int            `json:"event_id"` | 	RestartIfStopped       bool           `json:"restart_if_stopped"` | ||||||
| 	EventIDWildcard  bool           `json:"event_id_is_wildcard"` | 	LogName                string         `json:"log_name"` | ||||||
| 	EventType        string         `json:"event_type"` | 	EventID                int            `json:"event_id"` | ||||||
| 	EventSource      string         `json:"event_source"` | 	EventIDWildcard        bool           `json:"event_id_is_wildcard"` | ||||||
| 	EventMessage     string         `json:"event_message"` | 	EventType              string         `json:"event_type"` | ||||||
| 	FailWhen         string         `json:"fail_when"` | 	EventSource            string         `json:"event_source"` | ||||||
| 	SearchLastDays   int            `json:"search_last_days"` | 	EventMessage           string         `json:"event_message"` | ||||||
|  | 	FailWhen               string         `json:"fail_when"` | ||||||
|  | 	SearchLastDays         int            `json:"search_last_days"` | ||||||
| } | } | ||||||
|  |  | ||||||
| type AllChecks struct { | type AllChecks struct { | ||||||
| @@ -188,15 +190,17 @@ type AllChecks struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| type TaskAction struct { | type TaskAction struct { | ||||||
| 	ActionType string   `json:"type"` | 	ActionType             string   `json:"type"` | ||||||
| 	Command    string   `json:"command"` | 	Command                string   `json:"command"` | ||||||
| 	Shell      string   `json:"shell"` | 	Shell                  string   `json:"shell"` | ||||||
| 	ScriptName string   `json:"script_name"` | 	ScriptName             string   `json:"script_name"` | ||||||
| 	Code       string   `json:"code"` | 	Code                   string   `json:"code"` | ||||||
| 	Args       []string `json:"script_args"` | 	Args                   []string `json:"script_args"` | ||||||
| 	Timeout    int      `json:"timeout"` | 	Timeout                int      `json:"timeout"` | ||||||
| 	RunAsUser  bool     `json:"run_as_user"` | 	RunAsUser              bool     `json:"run_as_user"` | ||||||
| 	EnvVars    []string `json:"env_vars"` | 	EnvVars                []string `json:"env_vars"` | ||||||
|  | 	NushellEnableConfig    bool     `json:"nushell_enable_config"` | ||||||
|  | 	DenoDefaultPermissions string   `json:"deno_default_permissions"` | ||||||
| } | } | ||||||
|  |  | ||||||
| type AutomatedTask struct { | type AutomatedTask struct { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 David Randall
					David Randall