diff --git a/.gitignore b/.gitignore index 2de5db2f..65164567 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ guide/public \#*\# cscope.* cloudflared +cloudflared.pkg cloudflared.exe !cmd/cloudflared/ .DS_Store diff --git a/.mac_resources/scripts/postinstall b/.mac_resources/scripts/postinstall new file mode 100755 index 00000000..deb4ecbf --- /dev/null +++ b/.mac_resources/scripts/postinstall @@ -0,0 +1,7 @@ +#!/bin/bash + +# uninstall first in case this is an upgrade +/usr/local/bin/cloudflared service uninstall + +# install the new service using launchctl +/usr/local/bin/cloudflared service install \ No newline at end of file diff --git a/.mac_resources/uninstall.sh b/.mac_resources/uninstall.sh new file mode 100644 index 00000000..28563df9 --- /dev/null +++ b/.mac_resources/uninstall.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +/usr/local/bin/cloudflared service uninstall +rm /usr/local/bin/cloudflared +pkgutil --forget com.cloudflare.cloudflared \ No newline at end of file diff --git a/cmd/cloudflared/config/configuration.go b/cmd/cloudflared/config/configuration.go index 9512782f..ed72f3c0 100644 --- a/cmd/cloudflared/config/configuration.go +++ b/cmd/cloudflared/config/configuration.go @@ -4,6 +4,7 @@ import ( "errors" "os" "path/filepath" + "runtime" "github.com/cloudflare/cloudflared/validation" homedir "github.com/mitchellh/go-homedir" @@ -13,16 +14,54 @@ import ( ) var ( - // File names from which we attempt to read configuration. + // DefaultConfigFiles is the file names from which we attempt to read configuration. DefaultConfigFiles = []string{"config.yml", "config.yaml"} + // DefaultUnixConfigLocation is the primary location to find a config file + DefaultUnixConfigLocation = "/usr/local/etc/cloudflared" + + // DefaultUnixLogLocation is the primary location to find log files + DefaultUnixLogLocation = "/var/log/cloudflared" + // Launchd doesn't set root env variables, so there is default // Windows default config dir was ~/cloudflare-warp in documentation; let's keep it compatible - DefaultConfigDirs = []string{"~/.cloudflared", "~/.cloudflare-warp", "~/cloudflare-warp", "/usr/local/etc/cloudflared", "/etc/cloudflared"} + DefaultConfigDirs = []string{"~/.cloudflared", "~/.cloudflare-warp", "~/cloudflare-warp", "/etc/cloudflared", DefaultUnixConfigLocation} ) const DefaultCredentialFile = "cert.pem" +// DefaultConfigDirectory returns the default directory of the config file +func DefaultConfigDirectory() string { + if runtime.GOOS == "windows" { + path := os.Getenv("CFDPATH") + if path == "" { + path = filepath.Join(os.Getenv("ProgramFiles(x86)"), "cloudflared") + if _, err := os.Stat(path); os.IsNotExist(err) { //doesn't exist, so return an empty failure string + return "" + } + } + return path + } + return DefaultUnixConfigLocation +} + +// DefaultLogDirectory returns the default directory for log files +func DefaultLogDirectory() string { + if runtime.GOOS == "windows" { + return DefaultConfigDirectory() + } + return DefaultUnixLogLocation +} + +// DefaultConfigPath returns the default location of a config file +func DefaultConfigPath() string { + dir := DefaultConfigDirectory() + if dir == "" { + return DefaultConfigFiles[0] + } + return filepath.Join(dir, DefaultConfigFiles[0]) +} + // FileExists checks to see if a file exist at the provided path. func FileExists(path string) (bool, error) { f, err := os.Open(path) @@ -64,10 +103,43 @@ func FindDefaultConfigPath() string { return "" } +// FindOrCreateConfigPath returns the first path that contains a config file +// or creates one in the primary default path if it doesn't exist +func FindOrCreateConfigPath() string { + path := FindDefaultConfigPath() + + if path == "" { + // create the default directory if it doesn't exist + path = DefaultConfigPath() + if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil { + return "" + } + + // write a new config file out + file, err := os.Create(path) + if err != nil { + return "" + } + defer file.Close() + + logDir := DefaultLogDirectory() + os.MkdirAll(logDir, os.ModePerm) //try and create it. Doesn't matter if it succeed or not, only byproduct will be no logs + + c := Root{ + LogDirectory: logDir, + } + if err := yaml.NewEncoder(file).Encode(&c); err != nil { + return "" + } + } + + return path +} + // FindLogSettings gets the log directory and level from the config file func FindLogSettings() (string, string) { - configPath := FindDefaultConfigPath() - defaultDirectory := filepath.Dir(configPath) + configPath := FindOrCreateConfigPath() + defaultDirectory := DefaultLogDirectory() defaultLevel := "info" file, err := os.Open(configPath) diff --git a/cmd/cloudflared/config/manager_test.go b/cmd/cloudflared/config/manager_test.go index d64675af..7121fa54 100644 --- a/cmd/cloudflared/config/manager_test.go +++ b/cmd/cloudflared/config/manager_test.go @@ -49,9 +49,6 @@ func TestConfigChanged(t *testing.T) { os.Remove(filePath) }() c := &Root{ - OrgKey: "abcd", - ConfigType: "mytype", - CheckinInterval: 1, Forwarders: []Forwarder{ { URL: "test.daltoniam.com", diff --git a/cmd/cloudflared/config/model.go b/cmd/cloudflared/config/model.go index 7838fa01..e1c40233 100644 --- a/cmd/cloudflared/config/model.go +++ b/cmd/cloudflared/config/model.go @@ -34,14 +34,11 @@ type DNSResolver struct { // Root is the base options to configure the service type Root struct { - OrgKey string `json:"org_key" yaml:"orgKey"` - ConfigType string `json:"type"` - LogDirectory string `json:"log_directory" yaml:"logDirectory,omitempty"` - LogLevel string `json:"log_level" yaml:"logLevel"` - CheckinInterval int `json:"checkin_interval" yaml:"checkinInterval"` - Forwarders []Forwarder `json:"forwarders,omitempty"` - Tunnels []Tunnel `json:"tunnels,omitempty"` - Resolver DNSResolver `json:"resolver,omitempty"` + LogDirectory string `json:"log_directory" yaml:"logDirectory,omitempty"` + LogLevel string `json:"log_level" yaml:"logLevel,omitempty"` + Forwarders []Forwarder `json:"forwarders,omitempty" yaml:"forwarders,omitempty"` + Tunnels []Tunnel `json:"tunnels,omitempty" yaml:"tunnels,omitempty"` + Resolver DNSResolver `json:"resolver,omitempty" yaml:"resolver,omitempty"` } // Hash returns the computed values to see if the forwarder values change diff --git a/cmd/cloudflared/main.go b/cmd/cloudflared/main.go index 71263059..0dcd746c 100644 --- a/cmd/cloudflared/main.go +++ b/cmd/cloudflared/main.go @@ -182,7 +182,7 @@ func handleServiceMode(shutdownC chan struct{}) error { return err } - configPath := config.FindDefaultConfigPath() + configPath := config.FindOrCreateConfigPath() configManager, err := config.NewFileManager(f, configPath, logger) if err != nil { logger.Errorf("Cannot setup config file for monitoring: %s", err) diff --git a/make-mac-pkg.sh b/make-mac-pkg.sh new file mode 100755 index 00000000..95659452 --- /dev/null +++ b/make-mac-pkg.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +TARGET_DIRECTORY=".build" +BINARY_NAME="cloudflared" +VERSION=$(git describe --tags --always --dirty="-dev") +PRODUCT="cloudflared" + + +echo "building cloudflared" +make cloudflared + +echo "creating build directory" +mkdir ${TARGET_DIRECTORY} +mkdir ${TARGET_DIRECTORY}/contents +cp -r .mac_resources/scripts ${TARGET_DIRECTORY}/scripts + +echo "move cloudflared into the build directory" +mv $BINARY_NAME {$TARGET_DIRECTORY}/contents/${PRODUCT} + +echo "build the installer package" +pkgbuild --identifier com.cloudflare.${PRODUCT} \ + --version ${VERSION} \ + --scripts ${TARGET_DIRECTORY}/scripts \ + --root ${TARGET_DIRECTORY}/contents \ + --install-location /usr/local/bin \ + ${PRODUCT}.pkg + # TODO: our iOS/Mac account doesn't have this installer certificate type. + # need to find how we can get it --sign "Developer ID Installer: Cloudflare" \ + +echo "cleaning up the build directory" +rm -rf $TARGET_DIRECTORY diff --git a/wix.json b/wix.json new file mode 100644 index 00000000..3966a2ce --- /dev/null +++ b/wix.json @@ -0,0 +1,45 @@ +{ + "product": "cloudflared", + "company": "cloudflare", + "license": "LICENSE", + "upgrade-code": "23f90fdd-9328-47ea-ab52-5380855a4b12", + "files": { + "guid": "35e5e858-9372-4449-bf73-1cd6f7267128", + "items": [ + "cloudflared.exe" + ] + }, + "env": { + "guid": "6bb74449-d10d-4f4a-933e-6fc9fa006eae", + "vars": [ + { + "name": "CFDPATH", + "value": "[INSTALLDIR].", + "permanent": "no", + "system": "yes", + "action": "set", + "part": "all" + } + ] + }, + "shortcuts": {}, + "choco": { + "description": "cloudflared connects your machine or user identity to Cloudflare's global network.", + "project-url": "https://github.com/cloudflare/cloudflared", + "license-url": "https://github.com/cloudflare/cloudflared/blob/master/LICENSE" + }, + "hooks": [ + { + "command": "sc.exe create Cloudflared binPath=\"[INSTALLDIR]cloudflared.exe\" type=share start=auto DisplayName=\"Cloudflared\"", + "when": "install" + }, + { + "command": "sc.exe start Cloudflared", + "when": "install" + }, + { + "command": "sc.exe delete Cloudflared", + "when": "uninstall" + } + ] +} \ No newline at end of file