From 6d588c850e3b222f78dfdbcad1714b6a4cf3d7ab Mon Sep 17 00:00:00 2001 From: Muzzammil Shahid Date: Thu, 26 Sep 2024 19:14:25 +0500 Subject: [PATCH 1/9] Init go module --- go.mod | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 go.mod diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..13001e8 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/xconnio/wireguard-admin-service + +go 1.22 From 081b4e744c7046e3ab116e3e0db1a12ae89f193f Mon Sep 17 00:00:00 2001 From: Muzzammil Shahid Date: Thu, 26 Sep 2024 19:14:58 +0500 Subject: [PATCH 2/9] Add lint config file --- .golangci.yml | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 .golangci.yml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..2d762c8 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,183 @@ +run: + # default concurrency is a available CPU number + #concurrency: 4 + + # timeout for analysis, e.g. 30s, 5m, default is 1m + timeout: 5m + + # exit code when at least one issue was found, default is 1 + # issues-exit-code: 1 + + # include test files or not, default is true + tests: true + + # list of build tags, all linters use it. Default is empty list. + #build-tags: + # - mytag + + # which dirs to skip: issues from them won't be reported; + # can use regexp here: generated.*, regexp is applied on full path; + # default value is empty list, but default dirs are skipped independently + # from this option's value (see skip-dirs-use-default). + # "/" will be replaced by current OS file path separator to properly work + # on Windows. + #skip-dirs: + # - src/external_libs + # - autogenerated_by_my_lib + + # default is true. Enables skipping of directories: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + skip-dirs-use-default: false + + # which files to skip: they will be analyzed, but issues from them + # won't be reported. Default value is empty list, but there is + # no need to include all autogenerated files, we confidently recognize + # autogenerated files. If it's not please let us know. + # "/" will be replaced by current OS file path separator to properly work + # on Windows. + # skip-files: + # - export_test.go + + # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + # modules-download-mode: readonly|release|vendor + + # Allow multiple parallel golangci-lint instances running. + # If false (default) - golangci-lint acquires file lock on start. + allow-parallel-runners: false + +# output configuration options +output: +# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" +# format: colored-line-number + +# print lines of code with issue, default is true +# print-issued-lines: true + +# print linter name in the end of issue text, default is true +# print-linter-name: true + +# make issues output unique by line, default is true +# uniq-by-line: true + +# add a prefix to the output file references; default is no prefix + path-prefix: "" + +# all available settings of specific linters +# @see all available linters and options here: https://golangci-lint.run/usage/linters/ +linters-settings: + gci: + # Section configuration to compare against. + # Section names are case-insensitive and may contain parameters in (). + # The default order of sections is `standard > default > custom > blank > dot`, + # If `custom-order` is `true`, it follows the order of `sections` option. + # Default: ["standard", "default"] + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - prefix(github.com/xconnio) # Custom section: groups all imports with the specified Prefix. + # Skip generated files. + # Default: true + #skip-generated: false + # Enable custom order of sections. + # If `true`, make the section order the same as the order of `sections`. + # Default: false + custom-order: true + +linters: + # enable the following linters + enable: + - errcheck + - gosimple + - govet + - ineffassign + - misspell + - typecheck + - asciicheck + - bidichk + - contextcheck + - decorder + - durationcheck + - errorlint + - execinquery + - exportloopref + - gci + - gochecknoglobals + - goconst + - godot + - gofmt + #- gomnd + - gosec + - nakedret + - nilerr + - testpackage + - unused + - unconvert + - unparam + - lll + # disable everything else + disable-all: true + +issues: + # List of regexps of issue texts to exclude, empty list by default. + # But independently from this option we use default exclude patterns, + # it can be disabled by `exclude-use-default: false`. To list all + # excluded by default patterns execute `golangci-lint run --help` + # exclude: + # - abcdef + + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + # Exclude some linters from running on tests files. + - path: _test\.go + linters: + - gocyclo + - errcheck + - dupl + - gosec + + - path: export.*_test\.go + linters: + - testpackage + - gochecknoglobals + + # benchmarks are little noisy + - path: benchmarks/* + linters: + - unparam + - unused + + - path: examples/(serializers|authentications)\.go + linters: + - unused + + # disable noise from errcheck + - linters: + - errcheck + text: ".AbortWithReason" + + # Independently from option `exclude` we use default exclude patterns, + # it can be disabled by this option. To list all + # excluded by default patterns execute `golangci-lint run --help`. + # Default value for this option is true. + exclude-use-default: true + + # Maximum issues count per one linter. Set to 0 to disable. Default is 50. + max-per-linter: 0 + + # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. + max-same-issues: 0 + + # Show only new issues: if there are unstaged changes or untracked files, + # only those changes are analyzed, else only changes in HEAD~ are analyzed. + # It's a super-useful option for integration of golangci-lint into existing + # large codebase. It's not practical to fix all existing issues at the moment + # of integration: much better don't allow issues in new code. + # Default is false. + new: false From de0df8322c4d69038bb312161b4d1b66b334419e Mon Sep 17 00:00:00 2001 From: Muzzammil Shahid Date: Thu, 26 Sep 2024 19:15:53 +0500 Subject: [PATCH 3/9] Add gitignore file --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f11b75 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ From f373fde22cfcceb9c76eb3d87f508dea422eac85 Mon Sep 17 00:00:00 2001 From: Muzzammil Shahid Date: Thu, 26 Sep 2024 19:16:47 +0500 Subject: [PATCH 4/9] Add Makefile --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f149d6e --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +lint: + golangci-lint run +test: + go test -count=1 ./... -v From 9556bbc60a6759efc66a1ef28aa807f5ad6117c7 Mon Sep 17 00:00:00 2001 From: Muzzammil Shahid Date: Thu, 26 Sep 2024 19:17:18 +0500 Subject: [PATCH 5/9] Add basic CI --- .github/workflows/main.yaml | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/main.yaml diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml new file mode 100644 index 0000000..15a4fc5 --- /dev/null +++ b/.github/workflows/main.yaml @@ -0,0 +1,54 @@ +name: wireguard CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup go + uses: actions/setup-go@v3 + with: + go-version-file: 'go.mod' + cache: true + - run: go version + + - name: Pull in all Go dependencies + run: | + go mod vendor + + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + # version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` + version: latest + # skip all additional steps + skip-pkg-cache: true + skip-build-cache: true + + - name: Check that code is formatted via go fmt tool + run: | + if [ "$(gofmt -s -l . | grep -v vendor | wc -l)" -gt 0 ]; then + exit 1; + fi + + - name: Check that go modules are in synced state + run: | + go mod tidy -v + if [ -n "$(git status --porcelain go.mod go.sum)" ]; then + echo "Go modules are dirty or not in a good state. Please run go mod tidy" + exit 1; + fi + + - name: Run unit tests + run: | + make test From d27eeac18032b44dba80dca06dd196475ff677e4 Mon Sep 17 00:00:00 2001 From: Muzzammil Shahid Date: Sat, 28 Sep 2024 14:10:50 +0500 Subject: [PATCH 6/9] Add function to register new WireGuard user --- go.mod | 19 +++++ wireguard.go | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 wireguard.go diff --git a/go.mod b/go.mod index 13001e8..2508550 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,22 @@ module github.com/xconnio/wireguard-admin-service go 1.22 + +require ( + github.com/joho/godotenv v1.5.1 + github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 +) + +require ( + github.com/google/go-cmp v0.5.9 // indirect + github.com/josharian/native v1.1.0 // indirect + github.com/mdlayher/genetlink v1.3.2 // indirect + github.com/mdlayher/netlink v1.7.2 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + golang.org/x/crypto v0.8.0 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect +) diff --git a/wireguard.go b/wireguard.go new file mode 100644 index 0000000..b6af87f --- /dev/null +++ b/wireguard.go @@ -0,0 +1,204 @@ +package wireguard_admin_service + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "os/exec" + "strings" + + "github.com/joho/godotenv" + "github.com/skip2/go-qrcode" + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +// AddUser adds new wireguard user +func AddUser(clientName string) error { + params, err := godotenv.Read("/etc/wireguard/params") + if err != nil { + return fmt.Errorf("error loading .env file: %w", err) + } + + ipv4s, ipv6s, err := getExistingIPs(params["SERVER_WG_NIC"]) + if err != nil { + return fmt.Errorf("failed to get existing IPs: %w", err) + } + + baseIPv4 := getBaseIP(params["SERVER_WG_IPV4"], ".") + + lastOctet, err := generateRandomOctet() + if err != nil { + return fmt.Errorf("failed to generate random octet: %w", err) + } + var clientIPv4 string + for { + clientIPv4 = fmt.Sprintf("%s.%d", baseIPv4, lastOctet) + _, ok := ipv4s[clientIPv4+"/32"] + if !ok { + break + } + } + + baseIPv6 := getBaseIP(params["SERVER_WG_IPV6"], "::") + + var clientIPv6 string + for { + clientIPv6 = fmt.Sprintf("%s::%d", baseIPv6, lastOctet) + _, ok := ipv6s[clientIPv6+"/128"] + if !ok { + break + } + } + + clientPrivKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return fmt.Errorf("failed to generate client private key: %w", err) + } + clientPubKey := clientPrivKey.PublicKey() + + clientPreSharedKey, err := wgtypes.GenerateKey() + if err != nil { + return fmt.Errorf("failed to generate client private key: %w", err) + } + + endpoint := fmt.Sprintf("%s:%s", params["SERVER_PUB_IP"], params["SERVER_PORT"]) + + clientConfig := fmt.Sprintf(`[Interface] +PrivateKey = %s +Address = %s,%s +DNS = %s,%s + +[Peer] +PublicKey = %s +PresharedKey = %s +Endpoint = %s +AllowedIPs = %s`, clientPrivKey, clientIPv4, clientIPv6, params["CLIENT_DNS_1"], params["CLIENT_DNS_2"], + params["SERVER_PUB_KEY"], clientPreSharedKey, endpoint, params["ALLOWED_IPS"]) + + fmt.Println(clientConfig) + + err = generateQRCode(clientConfig, clientName) + if err != nil { + return fmt.Errorf("failed to generate QR Code: %w", err) + } + + peer := fmt.Sprintf(` +### Client %s +[Peer] +PublicKey = %s +PresharedKey =%s +AllowedIPs = %s/32,%s/128 +`, clientName, clientPubKey, clientPreSharedKey, clientIPv4, clientIPv6) + + fmt.Println(peer) + + err = appendToFile("/etc/wireguard/wg0.conf", peer) + if err != nil { + return fmt.Errorf("failed to append to file: %w", err) + } + + return syncWireGuardConfig(params["SERVER_WG_NIC"]) +} + +func getExistingIPs(deviceName string) (ipv4s, ipv6s map[string]string, err error) { + client, err := wgctrl.New() + if err != nil { + return + } + defer client.Close() + + device, err := client.Device(deviceName) + if err != nil { + return + } + + ipv4s = make(map[string]string) + ipv6s = make(map[string]string) + for _, peer := range device.Peers { + for _, ip := range peer.AllowedIPs { + if ip.IP.To4() != nil { + ipv4s[ip.String()] = "" + } else if ip.IP.To16() != nil { + ipv6s[ip.String()] = "" + } + } + } + + return +} + +func getBaseIP(ipStr, separator string) string { + parts := strings.Split(ipStr, separator) + + parts = parts[:len(parts)-1] + // Join the parts back together to form the base IP + baseIP := strings.Join(parts, separator) + return baseIP +} + +func generateRandomOctet() (int, error) { + n, err := rand.Int(rand.Reader, big.NewInt(254)) + if err != nil { + return 0, err + } + return int(n.Int64()) + 1, nil +} + +func appendToFile(filePath, content string) error { + f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer f.Close() + + _, err = f.WriteString(content) + return err +} + +func generateQRCode(clientConfig, clientName string) error { + qrFilePath := fmt.Sprintf("%s-client-qr.png", clientName) + err := qrcode.WriteFile(clientConfig, qrcode.Medium, 256, qrFilePath) + + return err +} + +func runCommand(command string, args []string, outputFile string) error { + cmd := exec.Command(command, args...) + + if outputFile != "" { + out, err := os.Create(outputFile) + if err != nil { + return fmt.Errorf("failed to create output file: %w", err) + } + defer out.Close() + cmd.Stdout = out + } + + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to run command '%s': %w", command, err) + } + + return nil +} + +// syncWireGuardConfig handles the entire process of stripping the configuration, +// syncing it with the WireGuard device, and cleaning up the temporary file. +func syncWireGuardConfig(serverWgNic string) error { + tempFile := "/tmp/wg-stripped.conf" + + if err := runCommand("wg-quick", []string{"strip", serverWgNic}, tempFile); err != nil { + return fmt.Errorf("error stripping configuration: %w", err) + } + + if err := runCommand("wg", []string{"syncconf", serverWgNic, tempFile}, ""); err != nil { + return fmt.Errorf("error syncing configuration: %w", err) + } + + if err := runCommand("rm", []string{tempFile}, ""); err != nil { + return fmt.Errorf("error removing temp file: %w", err) + } + + return nil +} From d9b5e7a16baf2779d7a9a0435bbdb8e2c8dd5e38 Mon Sep 17 00:00:00 2001 From: Muzzammil Shahid Date: Sat, 28 Sep 2024 14:26:51 +0500 Subject: [PATCH 7/9] Validate client name --- wireguard.go | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/wireguard.go b/wireguard.go index b6af87f..e760472 100644 --- a/wireguard.go +++ b/wireguard.go @@ -1,11 +1,14 @@ package wireguard_admin_service import ( + "bufio" "crypto/rand" + "errors" "fmt" "math/big" "os" "os/exec" + "regexp" "strings" "github.com/joho/godotenv" @@ -21,6 +24,10 @@ func AddUser(clientName string) error { return fmt.Errorf("error loading .env file: %w", err) } + if err = validateClientName(clientName, params["SERVER_WG_NIC"]); err != nil { + return err + } + ipv4s, ipv6s, err := getExistingIPs(params["SERVER_WG_NIC"]) if err != nil { return fmt.Errorf("failed to get existing IPs: %w", err) @@ -102,6 +109,40 @@ AllowedIPs = %s/32,%s/128 return syncWireGuardConfig(params["SERVER_WG_NIC"]) } +// validateClientName checks if the client name is valid and doesn't already exist in the file. +func validateClientName(clientName, serverWgNic string) error { + validNamePattern := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`) + if !validNamePattern.MatchString(clientName) { + return errors.New("invalid client name: only alphanumeric characters, underscores, and hyphens are allowed") + } + if len(clientName) >= 16 { + return errors.New("client name must be less than 16 characters") + } + + // Check if the client name already exists in the configuration file + filePath := fmt.Sprintf("/etc/wireguard/%s.conf", serverWgNic) + file, err := os.Open(filePath) + if err != nil { + return fmt.Errorf("unable to open configuration file: %w", err) + } + defer file.Close() + + clientExistsPattern := fmt.Sprintf("### Client %s", clientName) + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + if strings.TrimSpace(scanner.Text()) == clientExistsPattern { + return errors.New("a client with the specified name already exists, please choose another name") + } + } + + if scanner.Err() != nil { + return fmt.Errorf("error reading configuration file: %w", err) + } + + return nil +} + func getExistingIPs(deviceName string) (ipv4s, ipv6s map[string]string, err error) { client, err := wgctrl.New() if err != nil { From fb619dc578839a8b3e55c95e29b9e133f9cca541 Mon Sep 17 00:00:00 2001 From: Muzzammil Shahid Date: Sat, 28 Sep 2024 19:17:49 +0500 Subject: [PATCH 8/9] Add http API to add new user --- cmd/http-service/main.go | 49 ++++++++++++++++++++++++++++++++++++++++ go.mod | 30 +++++++++++++++++++++--- wireguard.go | 4 ++-- 3 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 cmd/http-service/main.go diff --git a/cmd/http-service/main.go b/cmd/http-service/main.go new file mode 100644 index 0000000..d16be12 --- /dev/null +++ b/cmd/http-service/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "os" + + "github.com/gin-gonic/gin" + + "github.com/xconnio/wireguard-admin-service" +) + +type DeviceRequest struct { + DeviceName string `json:"device_name" binding:"required"` +} + +func main() { + r := gin.Default() + + const imageDir = "./qr-codes" + + if err := os.MkdirAll(imageDir, os.ModePerm); err != nil { + log.Fatal(err) + } + + r.Static("qr", imageDir) + + r.POST("/device", func(c *gin.Context) { + var req DeviceRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "device_name is required"}) + return + } + + if err := wireguard_admin_service.AddUser(req.DeviceName); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + qrCode := fmt.Sprintf("http://%s/qr/%s-client-qr.png", c.Request.Host, req.DeviceName) + + c.JSON(http.StatusOK, gin.H{ + "qr_code": qrCode, + }) + }) + + log.Fatalln(r.Run("0.0.0.0:8000")) +} diff --git a/go.mod b/go.mod index 2508550..032881a 100644 --- a/go.mod +++ b/go.mod @@ -3,20 +3,44 @@ module github.com/xconnio/wireguard-admin-service go 1.22 require ( + github.com/gin-gonic/gin v1.10.0 github.com/joho/godotenv v1.5.1 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 ) require ( + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/josharian/native v1.1.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect - golang.org/x/crypto v0.8.0 // indirect - golang.org/x/net v0.9.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.7.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/wireguard.go b/wireguard.go index e760472..566cea6 100644 --- a/wireguard.go +++ b/wireguard.go @@ -17,7 +17,7 @@ import ( "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) -// AddUser adds new wireguard user +// AddUser adds new wireguard user. func AddUser(clientName string) error { params, err := godotenv.Read("/etc/wireguard/params") if err != nil { @@ -199,7 +199,7 @@ func appendToFile(filePath, content string) error { } func generateQRCode(clientConfig, clientName string) error { - qrFilePath := fmt.Sprintf("%s-client-qr.png", clientName) + qrFilePath := fmt.Sprintf("qr-codes/%s-client-qr.png", clientName) err := qrcode.WriteFile(clientConfig, qrcode.Medium, 256, qrFilePath) return err From ac90d0108b8fc775bc28171259ab9a21616131bb Mon Sep 17 00:00:00 2001 From: Muzzammil Shahid Date: Mon, 30 Sep 2024 13:47:49 +0500 Subject: [PATCH 9/9] Save client config to a file --- cmd/http-service/main.go | 16 +++++++++++----- wireguard.go | 9 +++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cmd/http-service/main.go b/cmd/http-service/main.go index d16be12..4a69aac 100644 --- a/cmd/http-service/main.go +++ b/cmd/http-service/main.go @@ -18,13 +18,17 @@ type DeviceRequest struct { func main() { r := gin.Default() - const imageDir = "./qr-codes" - - if err := os.MkdirAll(imageDir, os.ModePerm); err != nil { + const qrDir = "./qr-codes" + if err := os.MkdirAll(qrDir, os.ModePerm); err != nil { log.Fatal(err) } + r.Static("qrs", qrDir) - r.Static("qr", imageDir) + const cfgDir = "./configs" + if err := os.MkdirAll(cfgDir, os.ModePerm); err != nil { + log.Fatal(err) + } + r.Static("configs", cfgDir) r.POST("/device", func(c *gin.Context) { var req DeviceRequest @@ -38,10 +42,12 @@ func main() { return } - qrCode := fmt.Sprintf("http://%s/qr/%s-client-qr.png", c.Request.Host, req.DeviceName) + qrCode := fmt.Sprintf("http://%s/qrs/%s-client-qr.png", c.Request.Host, req.DeviceName) + config := fmt.Sprintf("http://%s/configs/client-%s.conf", c.Request.Host, req.DeviceName) c.JSON(http.StatusOK, gin.H{ "qr_code": qrCode, + "config": config, }) }) diff --git a/wireguard.go b/wireguard.go index 566cea6..9d42980 100644 --- a/wireguard.go +++ b/wireguard.go @@ -81,10 +81,13 @@ DNS = %s,%s PublicKey = %s PresharedKey = %s Endpoint = %s -AllowedIPs = %s`, clientPrivKey, clientIPv4, clientIPv6, params["CLIENT_DNS_1"], params["CLIENT_DNS_2"], +AllowedIPs = %s +`, clientPrivKey, clientIPv4, clientIPv6, params["CLIENT_DNS_1"], params["CLIENT_DNS_2"], params["SERVER_PUB_KEY"], clientPreSharedKey, endpoint, params["ALLOWED_IPS"]) - fmt.Println(clientConfig) + if err = os.WriteFile(fmt.Sprintf("configs/client-%s.conf", clientName), []byte(clientConfig), 0600); err != nil { + return fmt.Errorf("failed to write client config: %w", err) + } err = generateQRCode(clientConfig, clientName) if err != nil { @@ -99,8 +102,6 @@ PresharedKey =%s AllowedIPs = %s/32,%s/128 `, clientName, clientPubKey, clientPreSharedKey, clientIPv4, clientIPv6) - fmt.Println(peer) - err = appendToFile("/etc/wireguard/wg0.conf", peer) if err != nil { return fmt.Errorf("failed to append to file: %w", err)