diff --git a/guide/cert.go b/cert/cert.go similarity index 89% rename from guide/cert.go rename to cert/cert.go index 127547f..df79ff4 100644 --- a/guide/cert.go +++ b/cert/cert.go @@ -1,4 +1,4 @@ -package guide +package cert import ( "crypto" @@ -121,10 +121,12 @@ func obtainCertificate(domain, email string, userKey *ecdsa.PrivateKey, serverKe // because we aren't running as root and can't bind a listener to port 80 and 443 // (used later when we attempt to pass challenges). Keep in mind that you still // need to proxy challenge traffic to port 5002 and 5001. + //err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "5002")) err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "")) if err != nil { return nil, err } + //err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", "5001")) err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", "")) if err != nil { return nil, err @@ -157,36 +159,42 @@ func obtainCertificate(domain, email string, userKey *ecdsa.PrivateKey, serverKe return certificates, nil } -func CreateCert(domain, email string) error { +func RequestCert(domain, email string) error { userKey, err := loadUserKey() if err != nil { logger.Warn("failed to load user key, trying to create one..") userKey, err = createAndSaveUserKey() + if err != nil { + return err + } + } else { + logger.Warn("found user.key, using exist user key") } cert, err := obtainCertificate(domain, email, userKey, nil) if err != nil { return err } - saveServerKeyAndCert(cert) + if err := saveServerKeyAndCert(cert); err != nil { + return common.NewError("failed to save cert").Base(err) + } return nil } func RenewCert(domain, email string) error { serverKey, err := loadServerKey() - userKey, err := loadUserKey() - if err != nil { return err } - + userKey, err := loadUserKey() + if err != nil { + return err + } cert, err := obtainCertificate(domain, email, userKey, serverKey) if err != nil { return err } - ioutil.WriteFile(domain+".key", cert.PrivateKey, os.ModePerm) - ioutil.WriteFile(domain+".crt", cert.Certificate, os.ModePerm) - data, err := json.Marshal(cert) - common.Must(err) - ioutil.WriteFile(domain+".json", data, os.ModePerm) + if err := saveServerKeyAndCert(cert); err != nil { + return common.NewError("failed to save cert").Base(err) + } return nil } diff --git a/guide/cert_test.go b/cert/cert_test.go similarity index 67% rename from guide/cert_test.go rename to cert/cert_test.go index 1515d4b..d83abae 100644 --- a/guide/cert_test.go +++ b/cert/cert_test.go @@ -1,4 +1,4 @@ -package guide +package cert import ( "testing" @@ -8,10 +8,14 @@ import ( func TestCreate(t *testing.T) { caDir = "https://127.0.0.1:14000/dir" - common.Must(CreateCert("localhost", "test@email.com")) + common.Must(RequestCert("localhost", "test@email.com")) } func TestRenew(t *testing.T) { caDir = "https://127.0.0.1:14000/dir" common.Must(RenewCert("localhost", "test@email.com")) } + +func TestCertGuide(t *testing.T) { + RequestCertGuide() +} diff --git a/cert/cli.go b/cert/cli.go new file mode 100644 index 0000000..5792268 --- /dev/null +++ b/cert/cli.go @@ -0,0 +1,133 @@ +package cert + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + + "github.com/p4gefau1t/trojan-go/common" +) + +type domainInfo struct { + Domain string + Email string +} + +func posString(slice []string, element string) int { + for index, elem := range slice { + if elem == element { + return index + } + } + return -1 +} + +func containsString(slice []string, element string) bool { + return !(posString(slice, element) == -1) +} + +func askForConfirmation() bool { + var response string + _, err := fmt.Scanln(&response) + if err != nil { + logger.Fatal(err) + } + okayResponses := []string{"y", "Y", "yes", "Yes", "YES"} + nokayResponses := []string{"n", "N", "no", "No", "NO"} + if containsString(okayResponses, response) { + return true + } else if containsString(nokayResponses, response) { + return false + } else { + fmt.Println("Please type yes or no and then press enter:") + return askForConfirmation() + } +} + +func RequestCertGuide() { + //caDir = "https://127.0.0.1:14000/dir" + logger.Info("Guide mode: request cert") + + logger.Warn("To perform a ACME challenge, trojan-go need the ROOT PRIVILEGE to bind port 80 and 443") + logger.Warn("Please make sure you HAVE sudo this program, and port 80/443 is NOT used by other process at this moment") + logger.Info("Continue? (y/n)") + + if !askForConfirmation() { + return + } + + data, err := ioutil.ReadFile("domain_info.json") + info := &domainInfo{} + + if err != nil { + fmt.Println("Your domain name:") + fmt.Scanf("%s", &info.Domain) + fmt.Println("Your email:") + fmt.Scanf("%s", &info.Email) + } else { + logger.Info("domain_info.json found") + if err := json.Unmarshal(data, info); err != nil { + logger.Error(common.NewError("failed to parse domain_info.json").Base(err)) + return + } + } + + fmt.Printf("Domain: %s, Email: %s\n", info.Domain, info.Email) + fmt.Println("Is that correct? (y/n)") + + if !askForConfirmation() { + return + } + + data, err = json.Marshal(info) + common.Must(err) + ioutil.WriteFile("domain_info.json", data, os.ModePerm) + + if err := RequestCert(info.Domain, info.Email); err != nil { + logger.Error(common.NewError("Failed to create cert").Base(err)) + return + } + + logger.Info("All done. Certificates has been saved to server.crt and server.key") + logger.Warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + logger.Warn("BACKUP DOMAIN_INFO.JSON, SERVER.KEY, SERVER.CRT AND USER.KEY TO A SAFE PLACE") + logger.Warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") +} + +func RenewCertGuide() { + //caDir = "https://127.0.0.1:14000/dir" + logger.Info("Guide mode: renew cert") + + logger.Warn("To perform a ACME challenge, trojan-go need the ROOT PRIVILEGE to bind port 80 and 443") + logger.Warn("Please make sure you HAVE sudo this program, and port 80/443 is NOT used by other process at this moment") + logger.Info("Continue? (y/n)") + + if !askForConfirmation() { + return + } + + data, err := ioutil.ReadFile("domain_info.json") + if err != nil { + logger.Error(err) + return + } + + info := &domainInfo{} + if err := json.Unmarshal(data, info); err != nil { + logger.Error(err) + } + + fmt.Printf("Domain: %s, Email: %s\n", info.Domain, info.Email) + fmt.Println("Is that correct? (y/n)") + + if !askForConfirmation() { + return + } + + if err := RenewCert(info.Domain, info.Email); err != nil { + logger.Error(common.NewError("Failed to renew cert").Base(err)) + return + } + logger.Info("All done") +} diff --git a/go.sum b/go.sum index 2251bf3..6b925a0 100644 --- a/go.sum +++ b/go.sum @@ -65,6 +65,7 @@ github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYut github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= @@ -79,8 +80,6 @@ github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSY github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-acme/lego v1.2.1 h1:J9ybY0p+1+3yzGVP/JAUuksO41soQJCIJhwsa6UOZ7o= -github.com/go-acme/lego v2.7.2+incompatible h1:ThhpPBgf6oa9X/vRd0kEmWOsX7+vmYdckmGZSb+FEp0= github.com/go-acme/lego/v3 v3.5.0 h1:/0+NJQK+hNwRznhCi+19lbEa4xufhe7wJZOVd5j486s= github.com/go-acme/lego/v3 v3.5.0/go.mod h1:TXodhTGOiWEqXDdgrzBoCtJ5R4L9lfOE68CTM0KGkT0= github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= @@ -158,8 +157,10 @@ github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXH github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= @@ -198,6 +199,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -235,6 +237,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY= github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY= @@ -335,6 +338,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -459,6 +463,7 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -473,6 +478,7 @@ gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/guide/guide.go b/guide/guide.go deleted file mode 100644 index 68d1c87..0000000 --- a/guide/guide.go +++ /dev/null @@ -1,22 +0,0 @@ -package guide - -import "fmt" - -func CertGuide() { - logger.Info("Guide mode: cert") - fmt.Println("Your domain name:") - var domain, email string - fmt.Scanf("%s", &domain) - fmt.Println("Your email:") - fmt.Scanf("%s", &email) - - err := CreateCert(domain, email) - if err != nil { - logger.Error("Failed to create cert") - logger.Error(err) - return - } - - logger.Info("Done. Certificates and keys have been saved.") - logger.Info("BACKUP SERVER.KEY, SERVER.CRT AND USER.KEY TO A SAFE PLACE") -} diff --git a/main.go b/main.go index 2c93d0c..f575a26 100644 --- a/main.go +++ b/main.go @@ -6,8 +6,8 @@ import ( "os" "os/signal" + "github.com/p4gefau1t/trojan-go/cert" "github.com/p4gefau1t/trojan-go/conf" - "github.com/p4gefau1t/trojan-go/guide" "github.com/p4gefau1t/trojan-go/log" "github.com/p4gefau1t/trojan-go/proxy" ) @@ -17,11 +17,14 @@ var logger = log.New(os.Stdout) func main() { logger.Info("Trojan-Go initializing...") configFile := flag.String("config", "config.json", "Config filename") - guideMode := flag.String("guide", "", "guide mode, use -guide cert to request a cert from letsencrypt") + guideMode := flag.String("cert", "", "use \"-cert request\" to request a cert from letsencrypt, or \"-cert renew\" to renew a cert") flag.Parse() switch *guideMode { - case "cert": - guide.CertGuide() + case "request": + cert.RequestCertGuide() + return + case "renew": + cert.RenewCertGuide() return default: }