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 }