diff --git a/bumper/__init__.py b/bumper/__init__.py index fda6461..c28e6aa 100644 --- a/bumper/__init__.py +++ b/bumper/__init__.py @@ -119,13 +119,10 @@ xmppserverlog.addHandler(xmpp_rotate) logging.getLogger("asyncio").setLevel(logging.CRITICAL + 1) # Ignore this logger -mqtt_listen_address = bumper_listen + mqtt_listen_port = 8883 -conf1_listen_address = bumper_listen conf1_listen_port = 443 -conf2_listen_address = bumper_listen conf2_listen_port = 8007 -xmpp_listen_address = bumper_listen xmpp_listen_port = 5223 @@ -163,21 +160,19 @@ async def start(): bumperlog.info("Starting Bumper") global mqtt_server - mqtt_server = MQTTServer((mqtt_listen_address, mqtt_listen_port)) + mqtt_server = MQTTServer((bumper_listen, mqtt_listen_port)) global mqtt_helperbot - mqtt_helperbot = MQTTHelperBot((mqtt_listen_address, mqtt_listen_port)) + mqtt_helperbot = MQTTHelperBot((bumper_listen, mqtt_listen_port)) global conf_server conf_server = ConfServer( - (conf1_listen_address, conf1_listen_port), usessl=True, helperbot=mqtt_helperbot + (bumper_listen, conf1_listen_port), usessl=True, helperbot=mqtt_helperbot ) global conf_server_2 conf_server_2 = ConfServer( - (conf2_listen_address, conf2_listen_port), - usessl=False, - helperbot=mqtt_helperbot, - ) + (bumper_listen, conf2_listen_port), usessl=False, helperbot=mqtt_helperbot + ) global xmpp_server - xmpp_server = XMPPServer((xmpp_listen_address, xmpp_listen_port)) + xmpp_server = XMPPServer((bumper_listen, xmpp_listen_port)) # Start web servers conf_server.confserver_app() @@ -1004,14 +999,14 @@ def create_certs(): def first_run(): create_certs() - def main(argv=None): import argparse global bumper_debug global bumper_listen global bumper_announce_ip - + if not argv: + argv = sys.argv[1:] # Set argv to argv[1:] if not passed into main try: if not ( @@ -1033,6 +1028,7 @@ def main(argv=None): help="announce address to bots on checkin", ) parser.add_argument("--debug", action="store_true", help="enable debug logs") + args = parser.parse_args(args=argv) if args.debug: diff --git a/create_certs/create_certs_linux b/create_certs/create_certs_linux index e809faa..7e57e04 100755 Binary files a/create_certs/create_certs_linux and b/create_certs/create_certs_linux differ diff --git a/create_certs/create_certs_osx b/create_certs/create_certs_osx index c985f63..308e263 100755 Binary files a/create_certs/create_certs_osx and b/create_certs/create_certs_osx differ diff --git a/create_certs/create_certs_rpi b/create_certs/create_certs_rpi index c678ef0..0b561aa 100755 Binary files a/create_certs/create_certs_rpi and b/create_certs/create_certs_rpi differ diff --git a/create_certs/create_certs_windows.exe b/create_certs/create_certs_windows.exe index 18bfa69..2c84b99 100755 Binary files a/create_certs/create_certs_windows.exe and b/create_certs/create_certs_windows.exe differ diff --git a/create_certs/src/create_certs.go b/create_certs/src/create_certs.go index 5eaa1a8..ce61b37 100644 --- a/create_certs/src/create_certs.go +++ b/create_certs/src/create_certs.go @@ -9,21 +9,82 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/pem" + "flag" + "fmt" "log" "math/big" "net" "os" + "path/filepath" "time" ) +var InBumperSan string +var OutCertDirectory string + +func setFlags() { + + exePath, _ := os.Executable() + currentDir, _ := os.Getwd() + + //certPath will be current working directory by defaultß + certPath, err := filepath.Abs(currentDir) + if err != nil { + log.Printf("Error: %v", err) + } + + //sanPath will be exe path /Bumper_SAN.txt by default + sanPath, err := filepath.Abs(filepath.Join(exePath, "..", "/Bumper_SAN.txt")) + if err != nil { + log.Printf("Error: %v", err) + } + + flag.StringVar(&InBumperSan, "inSAN", sanPath, "Input file containing a list of Subject Alternate Names (line separated)") + flag.StringVar(&OutCertDirectory, "out", certPath, "Directory to output certificates to") + + flag.Parse() + +} func main() { - make_CA() + setFlags() - signCert() + fmt.Printf("-------- Create_Certs --------\n") + + //get absolute path + outCertDirectory, _ := filepath.Abs(OutCertDirectory) + dexists, isdfile := pathExistsType(outCertDirectory) + if !dexists { + log.Fatalf("Certs directory doesn't exist: %v", outCertDirectory) + } + if isdfile { + log.Fatalf("Certs directory is a file, not a directory: %v", outCertDirectory) + } + + //get absolute path + inBumperSan, _ := filepath.Abs(InBumperSan) + bexists, isbfile := pathExistsType(inBumperSan) + if !bexists { + log.Printf("Bumper SAN doesn't exist, certificate won't contain Subject Alternate Names: %v\n", inBumperSan) + inBumperSan = "" + } + if bexists && !isbfile { + log.Printf("Bumper SAN is a directory instead of file, certificate won't contain Subject Alternate Names: %v\n", inBumperSan) + inBumperSan = "" + } + + fmt.Printf("-------- Starting Certificate Creation --------\n") + fmt.Printf("Options: \n Output Directory: %v\n Input SAN List: %v\n", outCertDirectory, inBumperSan) + + make_CA(outCertDirectory) + signCert(outCertDirectory, inBumperSan) + + fmt.Printf("-------- Certificate Creation Complete --------\n") } -func make_CA() { +func make_CA(outCertDirectory string) { + + fmt.Printf("-------- Creating CA Cert --------\n") priv, _ := rsa.GenerateKey(rand.Reader, 2048) pub := &priv.PublicKey @@ -46,40 +107,40 @@ func make_CA() { ca_b, err := x509.CreateCertificate(rand.Reader, ca, ca, pub, priv) if err != nil { - log.Println("create ca failed", err) - return + log.Fatalf("Create ca failed: %v", err) } // Public key - certOut, err := os.Create("ca.crt") + certOut, err := os.Create(filepath.Join(outCertDirectory, "ca.crt")) if err != nil { - log.Fatal("create ca.crt failed", err) + log.Fatalf("Create ca.crt failed: %v", err) } pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: ca_b}) certOut.Close() - log.Print("ca.crt created\n") + log.Printf("ca.crt created at %v\n", filepath.Join(outCertDirectory, "ca.crt")) // Private key - keyOut, err := os.OpenFile("ca.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + keyOut, err := os.OpenFile(filepath.Join(outCertDirectory, "ca.key"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { - log.Fatal("create ca.key failed", err) + log.Fatalf("Create ca.key failed: %v", err) } pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) keyOut.Close() - log.Print("ca.key created\n") + log.Printf("ca.key created at %v\n", filepath.Join(outCertDirectory, "ca.key")) } -func signCert() { +func signCert(outCertDirectory string, inBumperSan string) { + fmt.Printf("-------- Creating Server Cert --------\n") // Load CA - catls, err := tls.LoadX509KeyPair("ca.crt", "ca.key") + catls, err := tls.LoadX509KeyPair(filepath.Join(outCertDirectory, "ca.crt"), filepath.Join(outCertDirectory, "ca.key")) if err != nil { - log.Fatal("error loading ca cert", err) + log.Fatalf("Error loading ca cert: %v", err) } ca, err := x509.ParseCertificate(catls.Certificate[0]) if err != nil { - log.Fatal("error parsing ca cert", err) + log.Fatalf("Error parsing ca cert: %v", err) } hostname, _ := os.Hostname() @@ -109,10 +170,19 @@ func signCert() { //DNS/SAN names for cert dnsNames := []string{hostname, "localhost"} //Read SANs from file - if fileExists("Bumper_SAN.txt") { - sans, err := readLines("Bumper_SAN.txt") + //get absolute path + + bexists, isbfile := pathExistsType(inBumperSan) + if !bexists { + log.Print("Bumper SAN doesn't exist, certificate won't contain Subject Alternate Names") + } + if bexists && !isbfile { + log.Print("Bumper SAN is a directory instead of file, certificate won't contain Subject Alternate Names") + } + if bexists && isbfile { + sans, err := readLines(inBumperSan) if err != nil { - log.Fatalf("readLines: %s", err) + log.Printf("Error reading %v certificates will be created without Subject Alternate Names: %v", inBumperSan, err) } dnsNames = append(dnsNames, sans...) } @@ -138,25 +208,25 @@ func signCert() { } // Sign the certificate - cert_b, err := x509.CreateCertificate(rand.Reader, &template, ca, pubKey, catls.PrivateKey) + cert_b, err := x509.CreateCertificate(rand.Reader, &template, ca, pubKey, catls.PrivateKey) // Public key - certOut, err := os.Create("bumper.crt") + certOut, err := os.Create(filepath.Join(outCertDirectory, "bumper.crt")) if err != nil { - log.Fatal("create bumper.crt failed", err) + log.Fatalf("Create bumper.crt failed: %v", err) } pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: cert_b}) certOut.Close() - log.Print("bumper.crt created\n") + log.Printf("bumper.crt created at %v\n", filepath.Join(outCertDirectory, "bumper.crt")) // Private key - keyOut, err := os.OpenFile("bumper.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + keyOut, err := os.OpenFile(filepath.Join(outCertDirectory, "bumper.key"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { - log.Fatal("create bumper.key failed", err) + log.Fatalf("create bumper.key failed: %v", err) } pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}) keyOut.Close() - log.Print("bumper.key created\n") + log.Printf("bumper.key created at %v\n", filepath.Join(outCertDirectory, "bumper.key")) } func bigIntHash(n *big.Int) []byte { @@ -182,12 +252,11 @@ func readLines(path string) ([]string, error) { return lines, scanner.Err() } -// fileExists checks if a file exists and is not a directory before we -// try using it to prevent further errors. -func fileExists(filename string) bool { +// pathexistsType checks if a path exists and is a file or directory +func pathExistsType(filename string) (exists bool, isfile bool) { info, err := os.Stat(filename) if os.IsNotExist(err) { - return false + return false, false } - return !info.IsDir() + return true, !info.IsDir() } diff --git a/create_certs/src/create_certs_test.go b/create_certs/src/create_certs_test.go new file mode 100644 index 0000000..e645dc6 --- /dev/null +++ b/create_certs/src/create_certs_test.go @@ -0,0 +1,41 @@ +package main + +import ( + "flag" + "os" + "testing" +) + +func TestArgs(t *testing.T) { + + orArgs := os.Args + + flag.CommandLine = flag.NewFlagSet(orArgs[0], flag.ContinueOnError) + os.Args = []string{"cmd", "-inSAN", "123"} + setFlags() + + if InBumperSan != "123" { + t.Error("InBumperSan not set by arg") + } + + flag.CommandLine = flag.NewFlagSet(orArgs[0], flag.ContinueOnError) + os.Args = []string{"cmd", "-out", "456"} + setFlags() + + if OutCertDirectory != "456" { + t.Error("Out path not set by arg") + } + + flag.CommandLine = flag.NewFlagSet(orArgs[0], flag.ContinueOnError) + os.Args = []string{"cmd", "-inSAN", "san1", "-out", "out2"} + setFlags() + + if InBumperSan != "san1" { + t.Error("InBumperSan not set by arg") + } + if OutCertDirectory != "out2" { + t.Error("Out path not set by arg") + } + + os.Args = orArgs +} diff --git a/docs/DNS_Setup.md b/docs/DNS_Setup.md index e90d378..1c5e071 100644 --- a/docs/DNS_Setup.md +++ b/docs/DNS_Setup.md @@ -26,7 +26,14 @@ If overriding DNS for the top-level domains isn't an option, you'll need to conf Not all domains have been documented at this point, and this list will be updated as more are identified/seen. The preferred way to ensure Bumper works is to override the full domains as above. - - Example: If you see `eco-{countrycode}-api.ecovacs.com` and you live in the US/North America you would use: `eco-us-api.ecovacs.com` +Replacement Examples: + - {countrycode} + - If you see `eco-{countrycode}-api.ecovacs.com` and you live in the US/North America you would use: `eco-us-api.ecovacs.com` + - **Note**: {countrycode} may also be generalized regions such as "EU". + - {region} + - If you see `portal-{region}.ecouser.net` and you live in the US/North America you would use: `portal-na.ecouser.net` + - **Note**: {region} may also be generalized regions such as "EU". + | Address | Description | | --------------------------------------- | ---------------------------------------------- | @@ -38,11 +45,14 @@ Not all domains have been documented at this point, and this list will be update | `gl-{countrycode}-api.ecovacs.com` | Used by EcoVacs Home app | | `gl-{countrycode}-openapi.ecovacs.com` | Used by EcoVacs Home app | | `portal-{countrycode}.ecouser.net` | Used for Login and Rest API | +| `portal-{region}.ecouser.net` | Used for Login and Rest API | | `portal-ww.ecouser.net` | Used for various Rest APIs | | `msg-{countrycode}.ecouser.net` | Used for XMPP | +| `msg-{region}.ecouser.net` | Used for XMPP | | `msg-ww.ecouser.net` | Used for XMPP | -| `mq-ww.ecouser.net` | Used for MQTT | | `mq-{countrycode}.ecouser.net` | Used for MQTT | +| `mq-{region}.ecouser.net` | Used for MQTT | +| `mq-ww.ecouser.net` | Used for MQTT | | `gl-{countrycode}-api.ecovacs.com` | Used by Ecovacs Home app for API | | `recommender.ecovacs.com` | Used by Ecovacs Home app | | `bigdata-international.ecovacs.com` | Telemetry/tracking | diff --git a/tests/test_init.py b/tests/test_init.py index 0e3ca2c..7c1218e 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -35,8 +35,8 @@ async def test_start_stop(): b = bumper b.db = "tests/tmp.db" # Set db location for testing - b.conf1_listen_address = "0.0.0.0" - b.conf1_listen_port = 443 + b.conf1_listen_address = "127.0.0.1" + b.conf1_listen_port = 444 asyncio.create_task(b.start()) await asyncio.sleep(0.1) l.check_present(("bumper", "INFO", "Starting Bumper"))