| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- // Copyright (C) 2021 The Syncthing Authors.
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
- // You can obtain one at https://mozilla.org/MPL/2.0/.
- // Package generate implements the `syncthing generate` subcommand.
- package generate
- import (
- "bufio"
- "context"
- "crypto/tls"
- "fmt"
- "os"
- "github.com/syncthing/syncthing/lib/config"
- "github.com/syncthing/syncthing/lib/events"
- "github.com/syncthing/syncthing/lib/fs"
- "github.com/syncthing/syncthing/lib/locations"
- "github.com/syncthing/syncthing/lib/logger"
- "github.com/syncthing/syncthing/lib/protocol"
- "github.com/syncthing/syncthing/lib/syncthing"
- )
- type CLI struct {
- GUIUser string `placeholder:"STRING" help:"Specify new GUI authentication user name"`
- GUIPassword string `placeholder:"STRING" help:"Specify new GUI authentication password (use - to read from standard input)"`
- NoDefaultFolder bool `help:"Don't create the \"default\" folder on first startup" env:"STNODEFAULTFOLDER"`
- NoPortProbing bool `help:"Don't try to find free ports for GUI and listen addresses on first startup" env:"STNOPORTPROBING"`
- }
- func (c *CLI) Run(l logger.Logger) error {
- // Support reading the password from a pipe or similar
- if c.GUIPassword == "-" {
- reader := bufio.NewReader(os.Stdin)
- password, _, err := reader.ReadLine()
- if err != nil {
- return fmt.Errorf("failed reading GUI password: %w", err)
- }
- c.GUIPassword = string(password)
- }
- if err := Generate(l, locations.GetBaseDir(locations.ConfigBaseDir), c.GUIUser, c.GUIPassword, c.NoDefaultFolder, c.NoPortProbing); err != nil {
- return fmt.Errorf("failed to generate config and keys: %w", err)
- }
- return nil
- }
- func Generate(l logger.Logger, confDir, guiUser, guiPassword string, noDefaultFolder, skipPortProbing bool) error {
- dir, err := fs.ExpandTilde(confDir)
- if err != nil {
- return err
- }
- if err := syncthing.EnsureDir(dir, 0o700); err != nil {
- return err
- }
- locations.SetBaseDir(locations.ConfigBaseDir, dir)
- var myID protocol.DeviceID
- certFile, keyFile := locations.Get(locations.CertFile), locations.Get(locations.KeyFile)
- cert, err := tls.LoadX509KeyPair(certFile, keyFile)
- if err == nil {
- l.Warnln("Key exists; will not overwrite.")
- } else {
- cert, err = syncthing.GenerateCertificate(certFile, keyFile)
- if err != nil {
- return fmt.Errorf("create certificate: %w", err)
- }
- }
- myID = protocol.NewDeviceID(cert.Certificate[0])
- l.Infoln("Device ID:", myID)
- cfgFile := locations.Get(locations.ConfigFile)
- cfg, _, err := config.Load(cfgFile, myID, events.NoopLogger)
- if fs.IsNotExist(err) {
- if cfg, err = syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder, skipPortProbing); err != nil {
- return fmt.Errorf("create config: %w", err)
- }
- } else if err != nil {
- return fmt.Errorf("load config: %w", err)
- }
- ctx, cancel := context.WithCancel(context.Background())
- go cfg.Serve(ctx)
- defer cancel()
- var updateErr error
- waiter, err := cfg.Modify(func(cfg *config.Configuration) {
- updateErr = updateGUIAuthentication(l, &cfg.GUI, guiUser, guiPassword)
- })
- if err != nil {
- return fmt.Errorf("modify config: %w", err)
- }
- waiter.Wait()
- if updateErr != nil {
- return updateErr
- }
- if err := cfg.Save(); err != nil {
- return fmt.Errorf("save config: %w", err)
- }
- return nil
- }
- func updateGUIAuthentication(l logger.Logger, guiCfg *config.GUIConfiguration, guiUser, guiPassword string) error {
- if guiUser != "" && guiCfg.User != guiUser {
- guiCfg.User = guiUser
- l.Infoln("Updated GUI authentication user name:", guiUser)
- }
- if guiPassword != "" && guiCfg.Password != guiPassword {
- if err := guiCfg.SetPassword(guiPassword); err != nil {
- return fmt.Errorf("failed to set GUI authentication password: %w", err)
- }
- l.Infoln("Updated GUI authentication password.")
- }
- return nil
- }
|