github.com/quickfeed/quickfeed@v0.0.0-20240507093252-ed8ca812a09c/internal/env/cert.go (about)

     1  package env
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"os"
     8  	"path/filepath"
     9  	"regexp"
    10  	"strings"
    11  )
    12  
    13  const (
    14  	defaultDomain   = "127.0.0.1"
    15  	defaultCertFile = "fullchain.pem"
    16  	defaultKeyFile  = "privkey.pem"
    17  )
    18  
    19  // Domain returns the domain name where quickfeed will be served.
    20  // Domain should not include the server name.
    21  func Domain() string {
    22  	domain := os.Getenv("DOMAIN")
    23  	if domain == "" {
    24  		domain = defaultDomain
    25  	}
    26  	return domain
    27  }
    28  
    29  // WhiteList returns a list of domains that the server will create certificates for.
    30  func Whitelist() ([]string, error) {
    31  	domains := os.Getenv("QUICKFEED_WHITELIST")
    32  	if domains == "" {
    33  		return nil, errors.New("required whitelist is undefined")
    34  	}
    35  	if regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`).MatchString(domains) {
    36  		return nil, errors.New("whitelist contains IP addresses")
    37  	}
    38  	// Split domains by comma and remove whitespace and empty entries
    39  	domainList := make([]string, 0)
    40  	for _, domain := range strings.Split(strings.ReplaceAll(domains, " ", ""), ",") {
    41  		if domain == "" {
    42  			continue
    43  		}
    44  		if IsLocal(domain) {
    45  			return nil, fmt.Errorf("whitelist contains local/private domain: %s", domain)
    46  		}
    47  		domainList = append(domainList, domain)
    48  	}
    49  	if len(domainList) == 0 {
    50  		return nil, errors.New("required whitelist is undefined")
    51  	}
    52  	return domainList, nil
    53  }
    54  
    55  // CertFile returns the full path to the certificate file.
    56  // To specify a different file, use the QUICKFEED_CERT_FILE environment variable.
    57  func CertFile() string {
    58  	certFile := os.Getenv("QUICKFEED_CERT_FILE")
    59  	if certFile == "" {
    60  		// If cert file is not specified, use the default cert file.
    61  		certFile = filepath.Join(CertPath(), Domain(), defaultCertFile)
    62  	}
    63  	return certFile
    64  }
    65  
    66  // KeyFile returns the full path to the certificate key file.
    67  // To specify a different key, use the QUICKFEED_KEY_FILE environment variable.
    68  func KeyFile() string {
    69  	keyFile := os.Getenv("QUICKFEED_KEY_FILE")
    70  	if keyFile == "" {
    71  		// If cert key is not specified, use the default cert key.
    72  		keyFile = filepath.Join(CertPath(), Domain(), defaultKeyFile)
    73  	}
    74  	return keyFile
    75  }
    76  
    77  // CertPath returns the full path to the directory containing the certificates.
    78  // If QUICKFEED_CERT_PATH is not set, the default path $QUICKFEED/internal/config/certs is used.
    79  func CertPath() string {
    80  	certPath := os.Getenv("QUICKFEED_CERT_PATH")
    81  	if certPath == "" {
    82  		certPath = filepath.Join(Root(), "internal", "config", "certs")
    83  	}
    84  	return certPath
    85  }
    86  
    87  func IsLocal(domain string) bool {
    88  	ips, err := net.LookupIP(domain)
    89  	if err != nil {
    90  		return false
    91  	}
    92  	for _, ip := range ips {
    93  		if !(ip.IsLoopback() || ip.IsPrivate()) {
    94  			return false
    95  		}
    96  	}
    97  	return true
    98  }