diff --git a/cmd/certificate/main.go b/cmd/certificate/main.go new file mode 100644 index 0000000..9cf977a --- /dev/null +++ b/cmd/certificate/main.go @@ -0,0 +1,82 @@ +package main + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "log" + "math/big" + "net" + "os" + "time" +) + +func main() { + // создаём шаблон сертификата + cert := &x509.Certificate{ + // указываем уникальный номер сертификата + SerialNumber: big.NewInt(1658), + // заполняем базовую информацию о владельце сертификата + Subject: pkix.Name{ + Organization: []string{"Yandex.Praktikum"}, + Country: []string{"RU"}, + }, + // разрешаем использование сертификата для 127.0.0.1 и ::1 + IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}, + // сертификат верен, начиная со времени создания + NotBefore: time.Now(), + // время жизни сертификата — 10 лет + NotAfter: time.Now().AddDate(10, 0, 0), + SubjectKeyId: []byte{1, 2, 3, 4, 6}, + // устанавливаем использование ключа для цифровой подписи, + // а также клиентской и серверной авторизации + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature, + } + + // создаём новый приватный RSA-ключ длиной 4096 бит + // обратите внимание, что для генерации ключа и сертификата + // используется rand.Reader в качестве источника случайных данных + privateKey, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + log.Fatal(err) + } + + // создаём сертификат x.509 + certBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, &privateKey.PublicKey, privateKey) + if err != nil { + log.Fatal(err) + } + + // кодируем сертификат и ключ в формате PEM, который + // используется для хранения и обмена криптографическими ключами + var certPEM bytes.Buffer + err = pem.Encode(&certPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + }) + if err != nil { + log.Fatal(err) + } + + var privateKeyPEM bytes.Buffer + err = pem.Encode(&privateKeyPEM, &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(privateKey), + }) + if err != nil { + log.Fatal(err) + } + + // Сохраняем сертификат и приватный ключ в файлы cert.pem и private.pem + if err = os.WriteFile("cert.pem", certPEM.Bytes(), 0644); err != nil { + log.Fatal(err) + } + + if err = os.WriteFile("key.pem", privateKeyPEM.Bytes(), 0644); err != nil { + log.Fatal(err) + } +} diff --git a/internal/app/app.go b/internal/app/app.go index d6df4e5..d77b8ba 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -30,6 +30,7 @@ type App struct { router *gin.Engine urlHandler *handler.URLHandler deleteWorker *worker.DeleteWorker + enableTLS bool } // New создаёт и настраивает новое приложение: @@ -152,6 +153,7 @@ func New() (*App, error) { router: router, urlHandler: urlHandler, deleteWorker: deleteWorker, + enableTLS: cfg.Enable_HTTPS, }, nil } @@ -201,6 +203,9 @@ func (a *App) SetupRoutes() { // Run запускает HTTP-сервер. func (a *App) Run() error { + if a.enableTLS { + return a.server.ListenAndServeTLS("cert.pem", "key.pem") + } return a.server.ListenAndServe() } diff --git a/internal/config/flag/config.go b/internal/config/flag/config.go index 99101bf..806d69f 100644 --- a/internal/config/flag/config.go +++ b/internal/config/flag/config.go @@ -21,6 +21,7 @@ type ServerConfig struct { SecretKey string `env:"SECRET_KEY"` AuditFile string `env:"AUDIT_FILE"` AuditURL string `env:"AUDIT_URL"` + Enable_HTTPS bool `env:"ENABLE_HTTPS"` } var ( @@ -34,6 +35,7 @@ var ( secretKey *string auditFile *string auditURL *string + enableHTTPS *bool flagsOnce sync.Once ) @@ -45,9 +47,10 @@ func initFlags() { dsnValue = flag.String("d", "", "database DSN") deleteWorkerCount = flag.Int("w", 2, "number of delete worker channels") deleteChannelSize = flag.Int("c", 1000, "size of each delete channel buffer") - secretKey = flag.String("s", "my-super-secret-key-change-in-production", "secret key for signing cookies") + secretKey = flag.String("sk", "my-super-secret-key-change-in-production", "secret key for signing cookies") auditFile = flag.String("audit-file", "", "path to audit log file") auditURL = flag.String("audit-url", "", "URL of remote audit server") + enableHTTPS = flag.Bool("s", false, "enable HTTPS") } // NewServerConfig создаёт конфигурацию, читая флаги и переменные окружения. @@ -128,6 +131,16 @@ func NewServerConfig() *ServerConfig { cfg.AuditURL = *auditURL } + if envEnableHTTPS, ok := os.LookupEnv("ENABLE_HTTPS"); ok { + if val, err := strconv.ParseBool(envEnableHTTPS); err == nil { + cfg.Enable_HTTPS = val + } else { + cfg.Enable_HTTPS = *enableHTTPS + } + } else { + cfg.Enable_HTTPS = *enableHTTPS + } + return cfg }