diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index e01712aa6..5bf8e5242 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,110 +1,153 @@ { - "ImportPath": "github.com/arduino/arduino-create-agent", - "GoVersion": "go1.4.2", + "ImportPath": ".", + "GoVersion": "go1.4", "Deps": [ + { + "ImportPath": "github.com/Sirupsen/logrus", + "Comment": "v0.8.7-53-g446d1c1", + "Rev": "446d1c146faa8ed3f4218f056fcd165f6bcfda81" + }, + { + "ImportPath": "github.com/carlescere/scheduler", + "Comment": "0.1-13-g025e9f5", + "Rev": "025e9f58462112b9fb636708374467aef7161289" + }, { "ImportPath": "github.com/facchinm/go-serial", "Rev": "3cfbd2fab741f7c9d238cb3bd17980110c81bd46" }, + { + "ImportPath": "github.com/facchinm/go-serial-native", + "Rev": "6c62fb894d873784830ec370e85ab1f29c2e0324" + }, { "ImportPath": "github.com/facchinm/systray", "Rev": "b32308b0b662e45cde7c5986bc29def5d48bafbb" }, + { + "ImportPath": "github.com/getlantern/filepersist", + "Rev": "e91ecdee50cac4a38975041089abdddcb94c4e97" + }, { "ImportPath": "github.com/getlantern/golog", "Rev": "5245e761fd1c8e9ccba87de802a0f666ed55980f" }, { "ImportPath": "github.com/gin-gonic/gin", - "Comment": "v1.0rc1-128-gfc5e355", - "Rev": "fc5e3557242901e24016d4474168515434871dd5" + "Comment": "v1.0rc1-148-g52fcc5d", + "Rev": "52fcc5dbf6e94df33ad313858fb94b713e9d1b4a" }, { "ImportPath": "github.com/googollee/go-engine.io", - "Rev": "597faf3df88a01780a5881fafbcbccd9d5c3fab0" + "Rev": "a66cf68b24e56df0cacdc6041b93742f983a296a" }, { "ImportPath": "github.com/googollee/go-socket.io", - "Comment": "0.9.x-33-g9c83c02", - "Rev": "9c83c02fa6172eaea8252b6428e3cef3576c9746" + "Comment": "0.9.x-51-g14bb3d0", + "Rev": "14bb3d0368089a74cb52164a7a697cf404bda9c6" }, { "ImportPath": "github.com/gorilla/websocket", - "Rev": "a3ec486e6a7a41858210b0fc5d7b5df593b3c4a3" - }, - { - "ImportPath": "github.com/inconshreveable/go-update", - "Rev": "68f5725818189545231c1fd8694793d45f2fc529" + "Rev": "2dbddebb8266b93c5e6b119efb54e89043186f3f" }, { "ImportPath": "github.com/itsjamie/gin-cors", - "Rev": "bd9551838cd52133960a2f44ab990be71744b663" + "Rev": "9526714e382db4023de25bfdad89cec9b7446092" }, { "ImportPath": "github.com/kardianos/osext", "Rev": "6e7f843663477789fac7c02def0d0909e969b4e5" }, - { - "ImportPath": "github.com/kardianos/service", - "Rev": "1ab12303aaf4cf68a53a5717a31b5acd72c57019" - }, { "ImportPath": "github.com/kr/binarydist", "Rev": "9955b0ab8708602d411341e55fffd7e0700f86bd" }, + { + "ImportPath": "github.com/kr/fs", + "Rev": "2788f0dbd16903de03cb8186e5c7d97b69ad387b" + }, { "ImportPath": "github.com/manucorporat/sse", - "Rev": "c142f0f1baea5cef7f98a8a6c222f6134368c1f5" + "Rev": "fe6ea2c8e398672518ef204bf0fbd9af858d0e15" }, { "ImportPath": "github.com/mattn/go-colorable", - "Rev": "40e4aedc8fabf8c23e040057540867186712faa5" + "Rev": "3dac7b4f76f6e17fb39b768b89e3783d16e237fe" + }, + { + "ImportPath": "github.com/mattn/go-isatty", + "Rev": "56b76bdf51f7708750eac80fa38b952bb9f32639" + }, + { + "ImportPath": "github.com/mattn/go-shellwords", + "Comment": "v1.0.0", + "Rev": "f4e566c536cf69158e808ec28ef4182a37fdc981" }, { "ImportPath": "github.com/miekg/dns", - "Rev": "7864d445e5087e8d761dbefec43f29b92f7650eb" + "Rev": "75e6e86cc601825c5dbcd4e0c209eab180997cd7" }, { "ImportPath": "github.com/oleksandr/bonjour", - "Rev": "415cafc6ab8894ea7b7bcbed933ce2d8c611683c" + "Rev": "7ee314fe2bb898db0072d9af4b540b816fe7c6b5" + }, + { + "ImportPath": "github.com/pivotal-golang/archiver/extractor", + "Rev": "f598990ddfeda2767a09346acf844a7d216c1256" }, { - "ImportPath": "github.com/sanderhahn/gozip/patchzip", - "Rev": "85893825032e0136f506cc9e3f36d42d56305ee9" + "ImportPath": "github.com/pkg/sftp", + "Rev": "2bc00847a6f77f5d32fa46b0ab829f0531d73244" + }, + { + "ImportPath": "github.com/sfreiberg/simplessh", + "Rev": "e2df5a8be6f36be66ed1af2e8767a354788e902b" }, { "ImportPath": "github.com/skratchdot/open-golang/open", "Rev": "c8748311a7528d0ba7330d302adbc5a677ef9c9e" }, { - "ImportPath": "github.com/termie/go-shutil", - "Rev": "bcacb06fecaeec8dc42af03c87c6949f4a05c74c" + "ImportPath": "github.com/vharitonsky/iniflags", + "Comment": "v.1.0-28-g02b57ef", + "Rev": "02b57ef987a5ee59eedc7dcd93315a43f6dcc4a7" }, { - "ImportPath": "github.com/vharitonsky/iniflags", - "Comment": "v.1.0-21-g14f4b95", - "Rev": "14f4b95d09b99e2475e82c37a2f943ef2469a890" + "ImportPath": "github.com/xrash/smetrics", + "Rev": "81a89232431423f9140fa413823ce3045f02f19c" }, { - "ImportPath": "golang.org/x/net/context", - "Rev": "d9558e5c97f85372afee28cf2b6059d7d3818919" + "ImportPath": "golang.org/x/crypto/curve25519", + "Rev": "f18420efc3b4f8e9f3d51f6bd2476e92c46260e9" + }, + { + "ImportPath": "golang.org/x/crypto/ssh", + "Rev": "f18420efc3b4f8e9f3d51f6bd2476e92c46260e9" }, { - "ImportPath": "golang.org/x/net/internal/iana", - "Rev": "d9558e5c97f85372afee28cf2b6059d7d3818919" + "ImportPath": "golang.org/x/net/context", + "Rev": "84ba27dd5b2d8135e9da1395277f2c9333a2ffda" }, { "ImportPath": "golang.org/x/net/ipv4", - "Rev": "d9558e5c97f85372afee28cf2b6059d7d3818919" + "Rev": "84ba27dd5b2d8135e9da1395277f2c9333a2ffda" }, { "ImportPath": "golang.org/x/net/ipv6", - "Rev": "d9558e5c97f85372afee28cf2b6059d7d3818919" + "Rev": "84ba27dd5b2d8135e9da1395277f2c9333a2ffda" + }, + { + "ImportPath": "golang.org/x/sys/unix", + "Rev": "833a04a10549a95dc34458c195cbad61bbb6cb4d" }, { "ImportPath": "gopkg.in/bluesuncorp/validator.v5", - "Comment": "v5.10", - "Rev": "d2748d5ae5e5af5ec3a85e3a59bf0db9d741c82d" + "Comment": "v5.12", + "Rev": "d5acf1dac43705f8bfbb71d878e290e2bed3950b" + }, + { + "ImportPath": "gopkg.in/inconshreveable/go-update.v0", + "Rev": "d8b0b1d421aa1cbf392c05869f8abbc669bb7066" } ] } diff --git a/README.md b/README.md index 1c8921a25..9ca35fcee 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ arduino-create-agent ==================== -Version X.XX - Get the latest version of the Agent for all supported platforms: * [Windows](http://downloads.arduino.cc/CreateBridgeStable/ArduinoCreateAgent-1.1-windows-installer.exe) @@ -21,6 +19,16 @@ Please use the current latest version: * [MacOSX dev](http://downloads.arduino.cc/CreateBridge/staging/ArduinoCreateAgent-1.0-osx-installer.dmg) * [Linux x64 dev](http://downloads.arduino.cc/CreateBridge/staging/ArduinoCreateAgent-1.0-linux-x64-installer.run) +## Compiling + +`compile_webidebridge.sh` contains the cross-platform script we use to deploy the agent for all the supported platforms; it needs to be adjusted as per your `go` installation paths and OS. + +You can use `bootstrapPlatforms` function to compile the needed CGO-enabled environment + +Other prerequisites are: +* libappindicator (Linux only) +* [go-selfupdate] (https://github.com/sanbornm/go-selfupdate) if you want to test automatic updates + ## Submitting an issue Please attach the output of the commands running at the debug console if useful. diff --git a/certificates.go b/certificates.go new file mode 100644 index 000000000..bfa4d11ac --- /dev/null +++ b/certificates.go @@ -0,0 +1,332 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Generate a self-signed X.509 certificate for a TLS server. Outputs to +// 'cert.pem' and 'key.pem' and will overwrite existing files. + +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "io/ioutil" + "math/big" + "net" + "os" + "strings" + "text/template" + "time" + + log "github.com/Sirupsen/logrus" + "github.com/gin-gonic/gin" +) + +var ( + host = "localhost" + validFrom = "" + validFor = 365 * 24 * time.Hour * 2 // 2 years + rsaBits = 2048 +) + +func publicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &k.PublicKey + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +func pemBlockForKey(priv interface{}) *pem.Block { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} + case *ecdsa.PrivateKey: + b, err := x509.MarshalECPrivateKey(k) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err) + os.Exit(2) + } + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} + default: + return nil + } +} + +func generateKey(ecdsaCurve string) (interface{}, error) { + switch ecdsaCurve { + case "": + return rsa.GenerateKey(rand.Reader, rsaBits) + case "P224": + return ecdsa.GenerateKey(elliptic.P224(), rand.Reader) + case "P256": + return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + case "P384": + return ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + case "P521": + return ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + default: + return nil, fmt.Errorf("Unrecognized elliptic curve: %q", ecdsaCurve) + } +} + +func generateSingleCertificate(isCa bool) (*x509.Certificate, error) { + var notBefore time.Time + var err error + if len(validFrom) == 0 { + notBefore = time.Now() + } else { + notBefore, err = time.Parse("Jan 2 15:04:05 2006", validFrom) + if err != nil { + return nil, fmt.Errorf("Failed to parse creation date: %s\n", err.Error()) + } + } + + notAfter := notBefore.Add(validFor) + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + return nil, fmt.Errorf("failed to generate serial number: %s\n", err.Error()) + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Arduino LLC US"}, + Country: []string{"US"}, + CommonName: "localhost", + OrganizationalUnit: []string{"IT"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + hosts := strings.Split(host, ",") + for _, h := range hosts { + if ip := net.ParseIP(h); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, h) + } + } + + if isCa { + template.IsCA = true + template.KeyUsage |= x509.KeyUsageCertSign + template.Subject.CommonName = "Arduino" + } + + return &template, nil +} + +func generateCertificates() { + + os.Remove("ca.cert.pem") + os.Remove("ca.key.pem") + os.Remove("cert.pem") + os.Remove("key.pem") + + // Create the key for the certification authority + caKey, err := generateKey("P256") + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } + + keyOut, err := os.OpenFile("ca.key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } + pem.Encode(keyOut, pemBlockForKey(caKey)) + keyOut.Close() + log.Println("written ca.key.pem") + + // Create the certification authority + caTemplate, err := generateSingleCertificate(true) + + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } + + derBytes, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, publicKey(caKey), caKey) + + certOut, err := os.Create("ca.cert.pem") + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } + pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + certOut.Close() + log.Print("written ca.cert.pem") + + ioutil.WriteFile("ca.cert.cer", derBytes, 0644) + log.Print("written ca.cert.cer") + + // Create the key for the final certificate + key, err := generateKey("P256") + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } + + keyOut, err = os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } + pem.Encode(keyOut, pemBlockForKey(key)) + keyOut.Close() + log.Println("written key.pem") + + // Create the final certificate + template, err := generateSingleCertificate(false) + + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } + + derBytes, err = x509.CreateCertificate(rand.Reader, template, caTemplate, publicKey(key), caKey) + + certOut, err = os.Create("cert.pem") + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } + pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + certOut.Close() + log.Print("written cert.pem") + + ioutil.WriteFile("cert.cer", derBytes, 0644) + log.Print("written cert.cer") + +} + +func certHandler(c *gin.Context) { + if strings.Contains(c.Request.UserAgent(), "Firefox") { + c.Header("content-type", "application/x-x509-ca-cert") + c.File("ca.cert.cer") + return + } + noFirefoxTemplate.Execute(c.Writer, gin.H{ + "url": "http://" + c.Request.Host + c.Request.URL.String(), + }) +} + +const noFirefoxTemplateHTML = ` + +
+ + + + +You need to open this link in Firefox to trust this certificate: {{.host}}{{.url}}
+