2015-10-27 10:37:03 +00:00
|
|
|
// Copyright (C) 2014 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,
|
2017-02-09 06:52:18 +00:00
|
|
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
2015-10-27 10:37:03 +00:00
|
|
|
|
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/url"
|
|
|
|
"os"
|
2023-09-24 17:23:49 +00:00
|
|
|
"regexp"
|
2020-02-18 07:52:12 +00:00
|
|
|
"strconv"
|
2015-10-27 10:37:03 +00:00
|
|
|
"strings"
|
2020-11-20 13:21:54 +00:00
|
|
|
|
2021-11-08 12:32:04 +00:00
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
|
2020-11-20 13:21:54 +00:00
|
|
|
"github.com/syncthing/syncthing/lib/rand"
|
2015-10-27 10:37:03 +00:00
|
|
|
)
|
|
|
|
|
2018-09-11 21:25:24 +00:00
|
|
|
func (c GUIConfiguration) IsAuthEnabled() bool {
|
2023-10-15 12:10:41 +00:00
|
|
|
// This function should match isAuthEnabled() in syncthingController.js
|
2018-09-11 21:25:24 +00:00
|
|
|
return c.AuthMode == AuthModeLDAP || (len(c.User) > 0 && len(c.Password) > 0)
|
2015-10-27 10:37:03 +00:00
|
|
|
}
|
|
|
|
|
2022-07-28 15:32:45 +00:00
|
|
|
func (GUIConfiguration) IsOverridden() bool {
|
2018-09-21 12:28:57 +00:00
|
|
|
return os.Getenv("STGUIADDRESS") != ""
|
|
|
|
}
|
|
|
|
|
2015-10-27 10:37:03 +00:00
|
|
|
func (c GUIConfiguration) Address() string {
|
|
|
|
if override := os.Getenv("STGUIADDRESS"); override != "" {
|
|
|
|
// This value may be of the form "scheme://address:port" or just
|
|
|
|
// "address:port". We need to chop off the scheme. We try to parse it as
|
|
|
|
// an URL if it contains a slash. If that fails, return it as is and let
|
|
|
|
// some other error handling handle it.
|
|
|
|
|
|
|
|
if strings.Contains(override, "/") {
|
|
|
|
url, err := url.Parse(override)
|
|
|
|
if err != nil {
|
|
|
|
return override
|
|
|
|
}
|
2018-09-21 12:28:57 +00:00
|
|
|
if strings.HasPrefix(url.Scheme, "unix") {
|
|
|
|
return url.Path
|
|
|
|
}
|
2015-10-27 10:37:03 +00:00
|
|
|
return url.Host
|
|
|
|
}
|
|
|
|
|
|
|
|
return override
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.RawAddress
|
|
|
|
}
|
|
|
|
|
2020-02-18 07:52:12 +00:00
|
|
|
func (c GUIConfiguration) UnixSocketPermissions() os.FileMode {
|
|
|
|
perm, err := strconv.ParseUint(c.RawUnixSocketPermissions, 8, 32)
|
|
|
|
if err != nil {
|
|
|
|
// ignore incorrectly formatted permissions
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return os.FileMode(perm) & os.ModePerm
|
|
|
|
}
|
|
|
|
|
2018-09-21 12:28:57 +00:00
|
|
|
func (c GUIConfiguration) Network() string {
|
2023-10-02 06:40:03 +00:00
|
|
|
if override := os.Getenv("STGUIADDRESS"); override != "" {
|
2018-09-21 12:28:57 +00:00
|
|
|
url, err := url.Parse(override)
|
2023-10-02 06:40:03 +00:00
|
|
|
if err == nil && strings.HasPrefix(url.Scheme, "unix") {
|
2018-09-21 12:28:57 +00:00
|
|
|
return "unix"
|
|
|
|
}
|
2023-10-02 06:40:03 +00:00
|
|
|
return "tcp"
|
2018-09-21 12:28:57 +00:00
|
|
|
}
|
|
|
|
if strings.HasPrefix(c.RawAddress, "/") {
|
|
|
|
return "unix"
|
|
|
|
}
|
|
|
|
return "tcp"
|
|
|
|
}
|
|
|
|
|
2015-10-27 10:37:03 +00:00
|
|
|
func (c GUIConfiguration) UseTLS() bool {
|
2018-09-21 12:28:57 +00:00
|
|
|
if override := os.Getenv("STGUIADDRESS"); override != "" {
|
2023-10-02 06:40:03 +00:00
|
|
|
return strings.HasPrefix(override, "https:") || strings.HasPrefix(override, "unixs:")
|
2015-10-27 10:37:03 +00:00
|
|
|
}
|
|
|
|
return c.RawUseTLS
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c GUIConfiguration) URL() string {
|
2023-10-02 06:40:03 +00:00
|
|
|
if c.Network() == "unix" {
|
|
|
|
if c.UseTLS() {
|
|
|
|
return "unixs://" + c.Address()
|
|
|
|
}
|
|
|
|
return "unix://" + c.Address()
|
2018-09-21 12:28:57 +00:00
|
|
|
}
|
|
|
|
|
2015-10-27 10:37:03 +00:00
|
|
|
u := url.URL{
|
|
|
|
Scheme: "http",
|
|
|
|
Host: c.Address(),
|
|
|
|
Path: "/",
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.UseTLS() {
|
|
|
|
u.Scheme = "https"
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasPrefix(u.Host, ":") {
|
|
|
|
// Empty host, i.e. ":port", use IPv4 localhost
|
|
|
|
u.Host = "127.0.0.1" + u.Host
|
|
|
|
} else if strings.HasPrefix(u.Host, "0.0.0.0:") {
|
|
|
|
// IPv4 all zeroes host, convert to IPv4 localhost
|
|
|
|
u.Host = "127.0.0.1" + u.Host[7:]
|
|
|
|
} else if strings.HasPrefix(u.Host, "[::]:") {
|
|
|
|
// IPv6 all zeroes host, convert to IPv6 localhost
|
|
|
|
u.Host = "[::1]" + u.Host[4:]
|
|
|
|
}
|
|
|
|
|
|
|
|
return u.String()
|
|
|
|
}
|
|
|
|
|
2023-09-24 17:23:49 +00:00
|
|
|
// matches a bcrypt hash and not too much else
|
|
|
|
var bcryptExpr = regexp.MustCompile(`^\$2[aby]\$\d+\$.{50,}`)
|
|
|
|
|
|
|
|
// SetPassword takes a bcrypt hash or a plaintext password and stores it.
|
|
|
|
// Plaintext passwords are hashed. Returns an error if the password is not
|
|
|
|
// valid.
|
|
|
|
func (c *GUIConfiguration) SetPassword(password string) error {
|
|
|
|
if bcryptExpr.MatchString(password) {
|
|
|
|
// Already hashed
|
|
|
|
c.Password = password
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
2021-11-08 12:32:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
c.Password = string(hash)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CompareHashedPassword returns nil when the given plaintext password matches the stored hash.
|
|
|
|
func (c GUIConfiguration) CompareHashedPassword(password string) error {
|
|
|
|
configPasswordBytes := []byte(c.Password)
|
|
|
|
passwordBytes := []byte(password)
|
|
|
|
return bcrypt.CompareHashAndPassword(configPasswordBytes, passwordBytes)
|
|
|
|
}
|
|
|
|
|
2016-02-02 10:12:25 +00:00
|
|
|
// IsValidAPIKey returns true when the given API key is valid, including both
|
|
|
|
// the value in config and any overrides
|
2016-01-29 17:16:01 +00:00
|
|
|
func (c GUIConfiguration) IsValidAPIKey(apiKey string) bool {
|
|
|
|
switch apiKey {
|
|
|
|
case "":
|
|
|
|
return false
|
|
|
|
|
2016-02-02 10:12:25 +00:00
|
|
|
case c.APIKey, os.Getenv("STGUIAPIKEY"):
|
2016-01-29 17:16:01 +00:00
|
|
|
return true
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false
|
2015-10-27 10:37:03 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-26 21:14:12 +00:00
|
|
|
|
2020-11-20 13:21:54 +00:00
|
|
|
func (c *GUIConfiguration) prepare() {
|
|
|
|
if c.APIKey == "" {
|
|
|
|
c.APIKey = rand.String(32)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-26 21:14:12 +00:00
|
|
|
func (c GUIConfiguration) Copy() GUIConfiguration {
|
|
|
|
return c
|
|
|
|
}
|