golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/conf/store.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package conf
     7  
     8  import (
     9  	"errors"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  
    14  	"golang.zx2c4.com/wireguard/windows/conf/dpapi"
    15  )
    16  
    17  const (
    18  	configFileSuffix            = ".conf.dpapi"
    19  	configFileUnencryptedSuffix = ".conf"
    20  )
    21  
    22  func ListConfigNames() ([]string, error) {
    23  	configFileDir, err := tunnelConfigurationsDirectory()
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  	files, err := os.ReadDir(configFileDir)
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  	configs := make([]string, len(files))
    32  	i := 0
    33  	for _, file := range files {
    34  		name, err := NameFromPath(file.Name())
    35  		if err != nil {
    36  			continue
    37  		}
    38  		if !file.Type().IsRegular() {
    39  			continue
    40  		}
    41  		info, err := file.Info()
    42  		if err != nil {
    43  			continue
    44  		}
    45  		if info.Mode().Perm()&0o444 == 0 {
    46  			continue
    47  		}
    48  		configs[i] = name
    49  		i++
    50  	}
    51  	return configs[:i], nil
    52  }
    53  
    54  func LoadFromName(name string) (*Config, error) {
    55  	configFileDir, err := tunnelConfigurationsDirectory()
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	return LoadFromPath(filepath.Join(configFileDir, name+configFileSuffix))
    60  }
    61  
    62  func LoadFromPath(path string) (*Config, error) {
    63  	name, err := NameFromPath(path)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	bytes, err := os.ReadFile(path)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	if strings.HasSuffix(path, configFileSuffix) {
    72  		bytes, err = dpapi.Decrypt(bytes, name)
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  	}
    77  	return FromWgQuickWithUnknownEncoding(string(bytes), name)
    78  }
    79  
    80  func PathIsEncrypted(path string) bool {
    81  	return strings.HasSuffix(filepath.Base(path), configFileSuffix)
    82  }
    83  
    84  func NameFromPath(path string) (string, error) {
    85  	name := filepath.Base(path)
    86  	if !((len(name) > len(configFileSuffix) && strings.HasSuffix(name, configFileSuffix)) ||
    87  		(len(name) > len(configFileUnencryptedSuffix) && strings.HasSuffix(name, configFileUnencryptedSuffix))) {
    88  		return "", errors.New("Path must end in either " + configFileSuffix + " or " + configFileUnencryptedSuffix)
    89  	}
    90  	if strings.HasSuffix(path, configFileSuffix) {
    91  		name = strings.TrimSuffix(name, configFileSuffix)
    92  	} else {
    93  		name = strings.TrimSuffix(name, configFileUnencryptedSuffix)
    94  	}
    95  	if !TunnelNameIsValid(name) {
    96  		return "", errors.New("Tunnel name is not valid")
    97  	}
    98  	return name, nil
    99  }
   100  
   101  func (config *Config) Save(overwrite bool) error {
   102  	if !TunnelNameIsValid(config.Name) {
   103  		return errors.New("Tunnel name is not valid")
   104  	}
   105  	configFileDir, err := tunnelConfigurationsDirectory()
   106  	if err != nil {
   107  		return err
   108  	}
   109  	filename := filepath.Join(configFileDir, config.Name+configFileSuffix)
   110  	bytes := []byte(config.ToWgQuick())
   111  	bytes, err = dpapi.Encrypt(bytes, config.Name)
   112  	if err != nil {
   113  		return err
   114  	}
   115  	return writeLockedDownFile(filename, overwrite, bytes)
   116  }
   117  
   118  func (config *Config) Path() (string, error) {
   119  	if !TunnelNameIsValid(config.Name) {
   120  		return "", errors.New("Tunnel name is not valid")
   121  	}
   122  	configFileDir, err := tunnelConfigurationsDirectory()
   123  	if err != nil {
   124  		return "", err
   125  	}
   126  	return filepath.Join(configFileDir, config.Name+configFileSuffix), nil
   127  }
   128  
   129  func DeleteName(name string) error {
   130  	if !TunnelNameIsValid(name) {
   131  		return errors.New("Tunnel name is not valid")
   132  	}
   133  	configFileDir, err := tunnelConfigurationsDirectory()
   134  	if err != nil {
   135  		return err
   136  	}
   137  	return os.Remove(filepath.Join(configFileDir, name+configFileSuffix))
   138  }
   139  
   140  func (config *Config) Delete() error {
   141  	return DeleteName(config.Name)
   142  }