Skip to content

Commit

Permalink
Add basic Lets Encrypt integration
Browse files Browse the repository at this point in the history
  • Loading branch information
khlieng committed Dec 7, 2015
1 parent 10dfa26 commit 8fd98ca
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 6 deletions.
15 changes: 13 additions & 2 deletions api/api.go
Expand Up @@ -22,6 +22,9 @@ var (

type Config struct {
Port int
SSL bool
Cert string
Key string
Dir string
Debug bool

Expand Down Expand Up @@ -57,8 +60,16 @@ func Serve() {
})
}

log.Println("API listening on port", config.Port)
createRouter().Run(":" + strconv.Itoa(config.Port))
r := createRouter()
port := ":" + strconv.Itoa(config.Port)

if config.SSL {
log.Println("[HTTP] API listening on port", config.Port)
r.RunTLS(port, config.Cert, config.Key)
} else {
log.Println("[HTTPS] API listening on port", config.Port)
r.Run(port)
}
}

func openStore(p string) {
Expand Down
16 changes: 13 additions & 3 deletions cli/castcloud.go
Expand Up @@ -33,20 +33,29 @@ func init() {

cobra.OnInitialize(func() {
dir = viper.GetString("dir")
os.Mkdir(dir, 0777)
os.MkdirAll(dir, 0777)
initConfig()

viper.SetConfigName("config")
viper.AddConfigPath(dir)
viper.ReadInConfig()

api.Configure(&api.Config{
cfg := &api.Config{
Port: viper.GetInt("port"),
Debug: viper.GetBool("debug"),
Dir: dir,
CrawlInterval: viper.GetDuration("crawl.interval"),
MaxDownloadConnections: viper.GetInt("crawl.max_conn"),
})
}

sslPath := path.Join(dir, "ssl")
if _, err := os.Stat(sslPath); err == nil {
cfg.SSL = true
cfg.Cert = path.Join(sslPath, "cert")
cfg.Key = path.Join(sslPath, "key")
}

api.Configure(cfg)
})
}

Expand All @@ -60,6 +69,7 @@ func addCommands() {
usersCmd.AddCommand(usersAddCmd)
usersCmd.AddCommand(usersRemoveCmd)
castcloudCmd.AddCommand(usersCmd)
castcloudCmd.AddCommand(sslCmd)
}

func bindFlags() {
Expand Down
92 changes: 92 additions & 0 deletions cli/ssl.go
@@ -0,0 +1,92 @@
package cli

import (
"crypto/rand"
"crypto/rsa"
"fmt"
"io/ioutil"
"log"
"os"
"path"

"github.com/Castcloud/castcloud-go-server/Godeps/_workspace/src/github.com/spf13/cobra"
"github.com/xenolf/lego/acme"
)

const caURL = "https://acme-v01.api.letsencrypt.org/directory"
const rsaKeySize = 2048

var sslCmd = &cobra.Command{
Use: "ssl <domain>",
Short: "Enable SSL",
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Println("Usage: ssl <domain>")
return
}

sslDir := path.Join(dir, "ssl")
err := os.Mkdir(sslDir, 0777)
if err != nil && !os.IsExist(err) {
log.Fatal(err)
}

letsEncrypt(args[0], sslDir)
},
}

type acmeUser struct {
Registration *acme.RegistrationResource
key *rsa.PrivateKey
}

func (u acmeUser) GetEmail() string {
return ""
}

func (u acmeUser) GetRegistration() *acme.RegistrationResource {
return u.Registration
}

func (u acmeUser) GetPrivateKey() *rsa.PrivateKey {
return u.key
}

func letsEncrypt(domain, outputDir string) {
privateKey, err := rsa.GenerateKey(rand.Reader, rsaKeySize)
if err != nil {
log.Fatal(err)
}

user := acmeUser{
key: privateKey,
}

client, err := acme.NewClient(caURL, &user, rsaKeySize, "443")
if err != nil {
log.Fatal(err)
}

reg, err := client.Register()
if err != nil {
log.Fatal(err)
}
user.Registration = reg

err = client.AgreeToTOS()
if err != nil {
log.Fatal(err)
}

certs, errors := client.ObtainCertificates([]string{domain}, false)
if len(errors) > 0 {
for k, err := range errors {
log.Println(k, err)
}

os.Exit(1)
}

ioutil.WriteFile(path.Join(outputDir, "cert"), certs[0].Certificate, 0777)
ioutil.WriteFile(path.Join(outputDir, "key"), certs[0].PrivateKey, 0777)
}
8 changes: 7 additions & 1 deletion config.default.toml
@@ -1,7 +1,13 @@
port = 3000

# Not implemented
[https]
port = 443
# Redirect http to https
redirect = true

[crawl]
# How often feeds should be fetched
interval = "15m"
# Maximum number of connections to use when fetching feeds
max_conn = 128
max_conn = 128

0 comments on commit 8fd98ca

Please sign in to comment.