WIP: Rewrite package with napi-go #18

Draft
Sirherobrine23 wants to merge 3 commits from go-napi into main
10 changed files with 277 additions and 410 deletions
Showing only changes of commit 21312c7378 - Show all commits

View File

@@ -1,257 +0,0 @@
package addon
import (
"errors"
"fmt"
"net"
"net/netip"
"time"
"github.com/abhisekp/napi-go"
napiEntry "github.com/abhisekp/napi-go/entry"
"github.com/abhisekp/napi-go/js"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
func init() {
// napiEntry.Export("constant", func(env napi.Env, info napi.CallbackInfo) napi.Value { return nil })
// deleteInterface(name: string): Promise<void>;
// napiEntry.Export("deleteInterface", GetInterface)
napiEntry.Export("getConfig", GetInterface)
napiEntry.Export("setConfig", SetInterface)
}
type PkgInfo struct {
DriveVersion string `json:"driveVersion"`
}
type Peer struct {
PresharedKey string
KeepInterval int
Endpoint string
AllowedIPs []net.IPNet
RemoveMe bool
RxByte int
TxByte int
LastHandshake time.Time
}
type Config struct {
Name string
PrivateKey string
PublicKey string
PortListen int
Fwmark int
ReplacePeers bool
Address []netip.Addr
Peers map[string]*Peer
}
func mustBigInt(env napi.Env, v int) napi.Value {
b, _ := napi.CreateBigIntInt64(env, int64(v))
return b
}
func processArgs(env napi.Env, info napi.CallbackInfo) ([]js.Value, error) {
cbInfo, st := napi.GetCbInfo(env, info)
if st != napi.StatusOK {
return nil, napi.StatusError(st)
}
jsEnv := js.AsEnv(env)
args := make([]js.Value, len(cbInfo.Args))
for i, cbArg := range cbInfo.Args {
args[i] = js.Value{
Env: jsEnv,
Value: cbArg,
}
}
return args, nil
}
func (cfg Config) ToNapi(env napi.Env) napi.Value {
obj := map[string]any{}
addrs := []string{}
peers := map[string]map[string]any{}
for _, addr := range cfg.Address {
addrs = append(addrs, addr.String())
}
for pubKey, peer := range cfg.Peers {
peerAddr := []string{}
for _, addr := range peer.AllowedIPs {
peerAddr = append(peerAddr, addr.String())
}
peers[pubKey] = map[string]any{
"presharedKey": peer.PresharedKey,
"keepInterval": peer.KeepInterval,
"endpoint": peer.Endpoint,
"allowdIPs": peerAddr,
"lastHandshake": peer.LastHandshake,
"rxBytes": mustBigInt(env, peer.RxByte),
"txBytes": mustBigInt(env, peer.TxByte),
}
}
obj["privateKey"] = cfg.PrivateKey
obj["publicKey"] = cfg.PrivateKey
obj["portListen"] = cfg.PortListen
obj["fwmark"] = cfg.Fwmark
obj["fwmark"] = cfg.Fwmark
obj["address"] = addrs
obj["peers"] = peers
return js.AsEnv(env).ValueOf(obj).Value
}
func mustNapi[T any](v T, _ napi.Status) T {
return v
}
func (cfg *Config) FromNapi(env napi.Env, info napi.CallbackInfo) error {
args, err := processArgs(env, info)
if err != nil {
return err
} else if len(args) == 0 {
return errors.New("return config to Wireguard interface")
}
configValue := args[0].Value
if !mustNapi(napi.HasNamedProperty(env, configValue, "name")) {
return fmt.Errorf("set wireguard interface name!")
} else if !mustNapi(napi.HasNamedProperty(env, configValue, "privateKey")) {
return fmt.Errorf("require privateKey to wireguard interface")
}
cfg.Name = mustNapi(napi.GetValueStringUtf8(env, mustNapi(napi.GetNamedProperty(env, configValue, "name"))))
cfg.PrivateKey = mustNapi(napi.GetValueStringUtf8(env, mustNapi(napi.GetNamedProperty(env, configValue, "privateKey"))))
if mustNapi(napi.HasNamedProperty(env, configValue, "publicKey")) {
cfg.PublicKey = mustNapi(napi.GetValueStringUtf8(env, mustNapi(napi.GetNamedProperty(env, configValue, "publicKey"))))
}
if mustNapi(napi.HasNamedProperty(env, configValue, "portListen")) {
cfg.PortListen = int(mustNapi(napi.GetValueInt32(env, mustNapi(napi.GetNamedProperty(env, configValue, "portListen")))))
}
if mustNapi(napi.HasNamedProperty(env, configValue, "fwmark")) {
cfg.Fwmark = int(mustNapi(napi.GetValueInt64(env, mustNapi(napi.GetNamedProperty(env, configValue, "fwmark")))))
}
if mustNapi(napi.HasNamedProperty(env, configValue, "replacePeers")) {
cfg.ReplacePeers = mustNapi(napi.GetValueBool(env, mustNapi(napi.GetNamedProperty(env, configValue, "replacePeers"))))
}
if mustNapi(napi.IsArray(env, mustNapi(napi.GetNamedProperty(env, configValue, "address")))) {
arrayValue := mustNapi(napi.GetNamedProperty(env, configValue, "address"))
sliceSize := mustNapi(napi.GetArrayLength(env, arrayValue))
cfg.Address = make([]netip.Addr, sliceSize)
for index := range sliceSize {
addrStr := mustNapi(napi.GetValueStringUtf8(env, mustNapi(napi.GetElement(env, arrayValue, index))))
if cfg.Address[index], err = netip.ParseAddr(addrStr); err != nil {
return fmt.Errorf("%s: %s", addrStr, err)
}
}
}
if mustNapi(napi.HasNamedProperty(env, configValue, "peers")) {
cfg.Peers = map[string]*Peer{}
peers := mustNapi(napi.GetNamedProperty(env, configValue, "peers"))
keys := mustNapi(napi.GetPropertyNames(env, peers))
keysSize := mustNapi(napi.GetArrayLength(env, keys))
for index := range keysSize {
publicKey := mustNapi(napi.GetValueStringUtf8(env, mustNapi(napi.GetElement(env, keys, index))))
peerObj := mustNapi(napi.GetNamedProperty(env, peers, publicKey))
if mustNapi(napi.HasNamedProperty(env, peerObj, "removeMe")) && mustNapi(napi.GetValueBool(env, mustNapi(napi.GetNamedProperty(env, peers, "removeMe")))) {
cfg.Peers[publicKey] = &Peer{RemoveMe: true}
} else {
peerInfo := &Peer{}
cfg.Peers[publicKey] = peerInfo
if mustNapi(napi.HasNamedProperty(env, peerObj, "presharedKey")) {
peerInfo.PresharedKey = mustNapi(napi.GetValueStringUtf8(env, mustNapi(napi.GetNamedProperty(env, peerObj, "presharedKey"))))
}
if mustNapi(napi.HasNamedProperty(env, peerObj, "keepInterval")) {
peerInfo.KeepInterval = int(mustNapi(napi.GetValueInt32(env, mustNapi(napi.GetNamedProperty(env, peerObj, "keepInterval")))))
}
if mustNapi(napi.HasNamedProperty(env, peerObj, "endpoint")) {
peerInfo.Endpoint = mustNapi(napi.GetValueStringUtf8(env, mustNapi(napi.GetNamedProperty(env, peerObj, "endpoint"))))
}
if mustNapi(napi.IsArray(env, mustNapi(napi.GetNamedProperty(env, peerObj, "allowedIPs")))) {
ips := mustNapi(napi.GetNamedProperty(env, peerObj, "allowedIPs"))
ipsSize := mustNapi(napi.GetArrayLength(env, ips))
peerInfo.AllowedIPs = make([]net.IPNet, ipsSize)
for index := range ipsSize {
addr := mustNapi(napi.GetValueStringUtf8(env, mustNapi(napi.GetElement(env, ips, index))))
if _, ip, err := net.ParseCIDR(addr); err == nil {
peerInfo.AllowedIPs[index] = *ip
} else {
ipAddr, err := netip.ParseAddr(addr)
if err != nil {
return err
}
if ipAddr.Is4() {
peerInfo.AllowedIPs[index] = net.IPNet{IP: net.ParseIP(addr), Mask: net.CIDRMask(31, 32)}
} else {
peerInfo.AllowedIPs[index] = net.IPNet{IP: net.ParseIP(addr), Mask: net.CIDRMask(64, 128)}
}
}
}
}
}
}
}
return nil
}
func pointValue[T any](v T) *T { return &v }
func (cfg Config) WgConfig() (wgtypes.Config, error) {
config := wgtypes.Config{
ListenPort: pointValue(cfg.PortListen),
FirewallMark: pointValue(cfg.Fwmark),
ReplacePeers: cfg.ReplacePeers,
Peers: []wgtypes.PeerConfig{},
}
pk, err := wgtypes.ParseKey(cfg.PrivateKey)
if err != nil {
return config, err
}
config.PrivateKey = pointValue(pk)
for peerKey, peerInfo := range cfg.Peers {
pb, err := wgtypes.ParseKey(peerKey)
if err != nil {
return config, err
}
if peerInfo.RemoveMe {
config.Peers = append(config.Peers, wgtypes.PeerConfig{
PublicKey: pb,
Remove: true,
})
} else {
peer := wgtypes.PeerConfig{PublicKey: pb, AllowedIPs: peerInfo.AllowedIPs}
if peerInfo.PresharedKey != "" {
pr, err := wgtypes.ParseKey(peerInfo.PresharedKey)
if err != nil {
return config, err
}
peer.PresharedKey = pointValue(pr)
}
if peerInfo.Endpoint != "" {
if peer.Endpoint, err = net.ResolveUDPAddr("udp", peerInfo.Endpoint); err != nil {
return config, err
}
}
peer.PersistentKeepaliveInterval = pointValue(time.Duration(peerInfo.KeepInterval))
// Append to config
config.Peers = append(config.Peers, peer)
}
}
return config, nil
}

View File

@@ -1,126 +0,0 @@
//go:build linux
package addon
import (
"errors"
"github.com/abhisekp/napi-go"
"github.com/abhisekp/napi-go/js"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
// args: [Name: string]
func GetInterface(env napi.Env, info napi.CallbackInfo) napi.Value {
args, err := processArgs(env, info)
if err != nil {
napi.Throw(env, js.AsEnv(env).ValueOf(err.Error()).Value)
return nil
}
promise, _ := napi.CreatePromise(env)
asyncResourceName, _ := napi.CreateStringUtf8(env, "addon/GetInterface")
devInfo := &Config{}
var worker napi.AsyncWork
worker, _ = napi.CreateAsyncWork(env, nil, asyncResourceName,
func(env napi.Env) {
if len(args) == 0 {
err = errors.New("Set interface name")
return
}
// Interface name
interfaceName, _ := napi.GetValueStringUtf8(args[0].Env.Env, args[0].Value)
// Get client to wireguard
var client *wgctrl.Client
if client, err = wgctrl.New(); err != nil {
return
}
defer client.Close()
// Get config
var dev *wgtypes.Device
if dev, err = client.Device(interfaceName); err != nil {
return
}
devInfo.PublicKey = dev.PublicKey.String()
devInfo.PrivateKey = dev.PrivateKey.String()
devInfo.PortListen = dev.ListenPort
devInfo.Fwmark = dev.FirewallMark
devInfo.Peers = map[string]*Peer{}
for _, peer := range dev.Peers {
devInfo.Peers[peer.PublicKey.String()] = &Peer{
PresharedKey: peer.PresharedKey.String(),
LastHandshake: peer.LastHandshakeTime,
KeepInterval: int(peer.PersistentKeepaliveInterval.Seconds()),
TxByte: int(peer.TransmitBytes),
RxByte: int(peer.ReceiveBytes),
AllowedIPs: peer.AllowedIPs,
}
if peer.Endpoint != nil {
devInfo.Peers[peer.PublicKey.String()].Endpoint = peer.Endpoint.String()
}
}
},
func(env napi.Env, status napi.Status) {
defer napi.DeleteAsyncWork(env, worker)
if status == napi.StatusCancelled {
return
} else if err != nil {
v, _ := napi.CreateError(env, nil, js.AsEnv(env).ValueOf(err.Error()).Value)
napi.RejectDeferred(env, promise.Deferred, v)
return
}
napi.ResolveDeferred(env, promise.Deferred, devInfo.ToNapi(env))
},
)
napi.QueueAsyncWork(env, worker)
return promise.Value
}
func SetInterface(env napi.Env, info napi.CallbackInfo) napi.Value {
devInfo := &Config{}
err := devInfo.FromNapi(env, info)
result, _ := napi.CreatePromise(env)
asyncResourceName, _ := napi.CreateStringUtf8(env, "addon/SetInterface")
var asyncWork napi.AsyncWork
asyncWork, _ = napi.CreateAsyncWork(env, nil, asyncResourceName,
func(env napi.Env) {
if err != nil {
return
}
// Get client to wireguard
var client *wgctrl.Client
if client, err = wgctrl.New(); err != nil {
return
}
defer client.Close()
var devConfig wgtypes.Config
if devConfig, err = devInfo.WgConfig(); err == nil {
err = client.ConfigureDevice(devInfo.Name, devConfig)
}
},
func(env napi.Env, status napi.Status) {
defer napi.DeleteAsyncWork(env, asyncWork)
if status == napi.StatusCancelled {
return
} else if err != nil {
v, _ := napi.CreateError(env, nil, js.AsEnv(env).ValueOf(err.Error()).Value)
napi.RejectDeferred(env, result.Deferred, v)
return
}
napi.ResolveDeferred(env, result.Deferred, devInfo.ToNapi(env))
napi.ResolveDeferred(env, result.Deferred, js.AsEnv(env).Undefined().Value)
},
)
napi.QueueAsyncWork(env, asyncWork)
return result.Value
}

View File

@@ -1,9 +0,0 @@
//go:build unix && !linux
package addon
import (
_ "golang.zx2c4.com/wireguard/conn"
_ "golang.zx2c4.com/wireguard/device"
_ "golang.zx2c4.com/wireguard/tun"
)

View File

@@ -1,3 +0,0 @@
//go:build windows
package addon

11
go.mod
View File

@@ -2,10 +2,13 @@ module sirherobrine23.com.br/Wireguard/Wireguard-tools.js
go 1.24.2
require github.com/abhisekp/napi-go v0.0.0-20250217102150-a60dbfea2dfd
require (
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.1
)
require (
github.com/google/btree v1.0.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/mdlayher/genetlink v1.3.2 // indirect
@@ -15,9 +18,5 @@ require (
golang.org/x/net v0.33.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 // indirect
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 // indirect
)

12
go.sum
View File

@@ -1,5 +1,3 @@
github.com/abhisekp/napi-go v0.0.0-20250217102150-a60dbfea2dfd h1:RsyP1mP+EDsLI+tT1gi3wudUoBzWq5Gl3adrgPLuvIE=
github.com/abhisekp/napi-go v0.0.0-20250217102150-a60dbfea2dfd/go.mod h1:fZYo8r5iHqF0JIr6OzTc+aGTcRPjAGnOmsSPleYKXTg=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -12,18 +10,14 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
@@ -36,3 +30,5 @@ golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdI
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ=
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ=
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.1 h1:qbAry0o+aR4ZPWqGu1LP2MzcAHL/JcwsOLK64ekLsFM=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.1/go.mod h1:ou35usxSZyinNvaeRHPlnxglSrmc9Wg9cfJ4mE5/9kA=

View File

@@ -1,5 +1,5 @@
package main
import _ "sirherobrine23.com.br/Wireguard/Wireguard-tools.js/addon"
import _ "sirherobrine23.com.br/Wireguard/Wireguard-tools.js/wg_addon"
func main() {}

47
wg_addon/addon.go Normal file
View File

@@ -0,0 +1,47 @@
package wg_addon
import (
"net"
"net/netip"
"time"
_ "unsafe"
"sirherobrine23.com.br/Sirherobrine23/napi-go"
_ "sirherobrine23.com.br/Sirherobrine23/napi-go/entry"
)
//go:linkname wg sirherobrine23.com.br/Sirherobrine23/napi-go/entry.Register
func wg(env napi.EnvType, export *napi.Object) {
getConfig, _ := napi.CreateFunction(env, "getConfig", GetInterface)
export.Set("getConfig", getConfig)
setConfig, _ := napi.CreateFunction(env, "setConfig", SetInterface)
export.Set("setConfig", setConfig)
// deleteInterface, _ := napi.CreateFunction(env, "deleteInterface", DeleteInterface)
// export.Set("deleteInterface", deleteInterface)
}
// Peer info
type Peer struct {
PresharedKey string `napi:"presharedKey"`
KeepInterval int `napi:"keepInterval"`
Endpoint string `napi:"endpoint"`
AllowedIPs []net.IPNet `napi:"allowedIPs"`
RemoveMe bool `napi:"removeMe"`
RxByte int `napi:"rxBytes"`
TxByte int `napi:"txBytes"`
LastHandshake time.Time `napi:"lastHandshake"`
}
// Wireguard interface configs
type Config struct {
Name string `napi:"name"`
PrivateKey string `napi:"privateKey"`
PublicKey string `napi:"publicKey"`
PortListen int `napi:"portListen"`
Fwmark int `napi:"fwmark"`
ReplacePeers bool `napi:"replacePeers"`
Address []netip.Addr `napi:"address"`
Peers map[string]*Peer `napi:"peers"`
}

32
wg_addon/unix.go Normal file
View File

@@ -0,0 +1,32 @@
//go:build unix && !linux
package wg_addon
import (
_ "golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
"sirherobrine23.com.br/Sirherobrine23/napi-go"
)
// Interface tunnels
var Tuns = map[string]*Tun{}
// Tunnel device
type Tun struct {
Tun tun.Device
Dev *device.Device
}
var GetConfig = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
return nil, nil
})
var SetConfig = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
return nil, nil
})
var DeleteInterface = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
return nil, nil
})

188
wg_addon/wgctrl.go Normal file
View File

@@ -0,0 +1,188 @@
//go:build linux || windows
package wg_addon
import (
"context"
"fmt"
"net"
"time"
"sirherobrine23.com.br/Sirherobrine23/napi-go"
"sirherobrine23.com.br/Sirherobrine23/napi-go/js"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
var SetInterface = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
if len(args) == 0 {
return nil, fmt.Errorf("set interface config")
}
var wgDevConfig Config
if err := js.ValueFrom(args[0], &wgDevConfig); err != nil {
return nil, err
}
promise, err := napi.CreatePromise(env)
if err != nil {
return nil, err
}
_, err = napi.CreateAyncWorker(env, context.Background(), func(env napi.EnvType, ctx context.Context) {
devInfo, err := wgDevConfig.WgConfig()
if err != nil {
napiErr, _ := napi.CreateError(env, err.Error())
promise.Reject(napiErr)
return
}
// Get client to wireguard
client, err := wgctrl.New()
if err != nil {
napiErr, _ := napi.CreateError(env, err.Error())
promise.Reject(napiErr)
return
}
defer client.Close()
// Set Config
if err := client.ConfigureDevice(wgDevConfig.Name, devInfo); err != nil {
napiErr, _ := napi.CreateError(env, err.Error())
promise.Reject(napiErr)
return
}
// Resolve promise
und, _ := env.Undefined()
promise.Resolve(und)
})
return promise, err
})
var GetInterface = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
if len(args) == 0 {
return nil, fmt.Errorf("set interface name")
}
interfaceName := napi.ToString(args[0])
typeof, err := interfaceName.Type()
if !(err == nil || typeof == napi.TypeString) {
return nil, fmt.Errorf("set interface name")
}
var config Config
{
interfaceName, _ := interfaceName.Utf8Value()
// Get client to wireguard
var client *wgctrl.Client
if client, err = wgctrl.New(); err != nil {
return nil, err
}
defer client.Close()
// Get config
var dev *wgtypes.Device
if dev, err = client.Device(interfaceName); err != nil {
return nil, err
}
config.FromWg(dev)
}
return js.ValueOf(env, config)
})
var DeleteInterface = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
if len(args) == 0 {
return nil, fmt.Errorf("set interface name")
}
interfaceName := napi.ToString(args[0])
typeof, err := interfaceName.Type()
if !(err == nil || typeof == napi.TypeString) {
return nil, fmt.Errorf("set interface name")
}
{
// interfaceName, _ := interfaceName.Utf8Value()
// // Get client to wireguard
// var client *wgctrl.Client
// if client, err = wgctrl.New(); err != nil {
// return nil, err
// }
// defer client.Close()
}
return nil, nil
})
func pointValue[T any](v T) *T { return &v }
func (cfg Config) WgConfig() (wgtypes.Config, error) {
config := wgtypes.Config{
ListenPort: pointValue(cfg.PortListen),
FirewallMark: pointValue(cfg.Fwmark),
ReplacePeers: cfg.ReplacePeers,
Peers: []wgtypes.PeerConfig{},
}
pk, err := wgtypes.ParseKey(cfg.PrivateKey)
if err != nil {
return config, err
}
config.PrivateKey = pointValue(pk)
for peerKey, peerInfo := range cfg.Peers {
pb, err := wgtypes.ParseKey(peerKey)
if err != nil {
return config, err
}
if peerInfo.RemoveMe {
config.Peers = append(config.Peers, wgtypes.PeerConfig{
PublicKey: pb,
Remove: true,
})
} else {
peer := wgtypes.PeerConfig{PublicKey: pb, AllowedIPs: peerInfo.AllowedIPs}
if peerInfo.PresharedKey != "" {
pr, err := wgtypes.ParseKey(peerInfo.PresharedKey)
if err != nil {
return config, err
}
peer.PresharedKey = pointValue(pr)
}
if peerInfo.Endpoint != "" {
if peer.Endpoint, err = net.ResolveUDPAddr("udp", peerInfo.Endpoint); err != nil {
return config, err
}
}
peer.PersistentKeepaliveInterval = pointValue(time.Duration(peerInfo.KeepInterval))
// Append to config
config.Peers = append(config.Peers, peer)
}
}
return config, nil
}
func (cfg *Config) FromWg(dev *wgtypes.Device) {
cfg.PublicKey = dev.PublicKey.String()
cfg.PrivateKey = dev.PrivateKey.String()
cfg.PortListen = dev.ListenPort
cfg.Fwmark = dev.FirewallMark
cfg.Peers = map[string]*Peer{}
for _, peer := range dev.Peers {
cfg.Peers[peer.PublicKey.String()] = &Peer{
PresharedKey: peer.PresharedKey.String(),
LastHandshake: peer.LastHandshakeTime,
KeepInterval: int(peer.PersistentKeepaliveInterval.Seconds()),
TxByte: int(peer.TransmitBytes),
RxByte: int(peer.ReceiveBytes),
AllowedIPs: peer.AllowedIPs,
}
if peer.Endpoint != nil {
cfg.Peers[peer.PublicKey.String()].Endpoint = peer.Endpoint.String()
}
}
}