mirror of
https://github.com/bolkedebruin/rdpgw.git
synced 2026-03-30 23:46:36 +00:00
Finalize rdp templating
This commit is contained in:
83
cmd/rdpgw/rdp/koanf/parsers/rdp/rdp.go
Normal file
83
cmd/rdpgw/rdp/koanf/parsers/rdp/rdp.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package rdp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RDP struct{}
|
||||
|
||||
func Parser() *RDP {
|
||||
return &RDP{}
|
||||
}
|
||||
|
||||
func (p *RDP) Unmarshal(b []byte) (map[string]interface{}, error) {
|
||||
r := bytes.NewReader(b)
|
||||
scanner := bufio.NewScanner(r)
|
||||
mp := make(map[string]interface{})
|
||||
|
||||
c := 0
|
||||
for scanner.Scan() {
|
||||
c++
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
fields := strings.SplitN(line, ":", 3)
|
||||
if len(fields) != 3 {
|
||||
return nil, fmt.Errorf("malformed line %d: %q", c, line)
|
||||
}
|
||||
|
||||
key := strings.TrimSpace(fields[0])
|
||||
t := strings.TrimSpace(fields[1])
|
||||
val := strings.TrimSpace(fields[2])
|
||||
|
||||
switch t {
|
||||
case "i":
|
||||
intValue, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse integer at line %d: %s", c, line)
|
||||
}
|
||||
mp[key] = intValue
|
||||
case "s":
|
||||
mp[key] = val
|
||||
default:
|
||||
return nil, fmt.Errorf("malformed line %d: %s", c, line)
|
||||
}
|
||||
}
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
func (p *RDP) Marshal(o map[string]interface{}) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
|
||||
keys := make([]string, 0, len(o))
|
||||
for k := range o {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
v := o[key]
|
||||
switch v.(type) {
|
||||
case bool:
|
||||
if v == true {
|
||||
fmt.Fprintf(&b, "%s:i:1", key)
|
||||
} else {
|
||||
fmt.Fprintf(&b, "%s:i:0", key)
|
||||
}
|
||||
case int:
|
||||
fmt.Fprintf(&b, "%s:i:%d", key, v)
|
||||
case string:
|
||||
fmt.Fprintf(&b, "%s:s:%s", key, v)
|
||||
default:
|
||||
return nil, fmt.Errorf("error marshalling")
|
||||
}
|
||||
fmt.Fprint(&b, "\r\n")
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
85
cmd/rdpgw/rdp/koanf/parsers/rdp/rdp_test.go
Normal file
85
cmd/rdpgw/rdp/koanf/parsers/rdp/rdp_test.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package rdp
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnmarshalRDPFile(t *testing.T) {
|
||||
rdp := Parser()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
cfg []byte
|
||||
expOutput map[string]interface{}
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
expOutput: map[string]interface{}{},
|
||||
},
|
||||
{
|
||||
name: "string",
|
||||
cfg: []byte(`username:s:user1`),
|
||||
expOutput: map[string]interface{}{
|
||||
"username": "user1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "integer",
|
||||
cfg: []byte(`session bpp:i:32`),
|
||||
expOutput: map[string]interface{}{
|
||||
"session bpp": 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multi",
|
||||
cfg: []byte("compression:i:1\r\nusername:s:user2\r\n"),
|
||||
expOutput: map[string]interface{}{
|
||||
"compression": 1,
|
||||
"username": "user2",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
outMap, err := rdp.Unmarshal(tc.cfg)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.expOutput, outMap)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRDP_Marshal(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
input map[string]interface{}
|
||||
output []byte
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "Empty RDP",
|
||||
input: map[string]interface{}{},
|
||||
output: []byte(nil),
|
||||
},
|
||||
{
|
||||
name: "Valid RDP all types",
|
||||
input: map[string]interface{}{
|
||||
"compression": 1,
|
||||
"session bpp": 32,
|
||||
"username": "user1",
|
||||
},
|
||||
output: []byte("compression:i:1\r\nsession bpp:i:32\r\nusername:s:user1\r\n"),
|
||||
},
|
||||
}
|
||||
|
||||
rdp := Parser()
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
out, err := rdp.Marshal(tc.input)
|
||||
assert.Equal(t, tc.output, out)
|
||||
assert.Equal(t, tc.err, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,10 @@ package rdp
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/bolkedebruin/rdpgw/cmd/rdpgw/rdp/koanf/parsers/rdp"
|
||||
"github.com/fatih/structs"
|
||||
"github.com/knadh/koanf/providers/file"
|
||||
"github.com/knadh/koanf/v2"
|
||||
"log"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@@ -81,21 +84,38 @@ type RdpSettings struct {
|
||||
RemoteApplicationProgram string `rdp:"remoteapplicationprogram"`
|
||||
}
|
||||
|
||||
type RdpBuilder struct {
|
||||
type Builder struct {
|
||||
Settings RdpSettings
|
||||
}
|
||||
|
||||
func NewRdp() *RdpBuilder {
|
||||
func NewBuilder() *Builder {
|
||||
c := RdpSettings{}
|
||||
|
||||
initStruct(&c)
|
||||
|
||||
return &RdpBuilder{
|
||||
return &Builder{
|
||||
Settings: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (rb *RdpBuilder) String() string {
|
||||
func NewBuilderFromFile(filename string) (*Builder, error) {
|
||||
c := RdpSettings{}
|
||||
initStruct(&c)
|
||||
|
||||
var k = koanf.New(".")
|
||||
if err := k.Load(file.Provider(filename), rdp.Parser()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := koanf.UnmarshalConf{Tag: "rdp"}
|
||||
if err := k.UnmarshalWithConf("", &c, t); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Builder{
|
||||
Settings: c,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (rb *Builder) String() string {
|
||||
var sb strings.Builder
|
||||
|
||||
addStructToString(rb.Settings, &sb)
|
||||
|
||||
@@ -11,7 +11,7 @@ const (
|
||||
)
|
||||
|
||||
func TestRdpBuilder(t *testing.T) {
|
||||
builder := NewRdp()
|
||||
builder := NewBuilder()
|
||||
builder.Settings.GatewayHostname = "my.yahoo.com"
|
||||
builder.Settings.AutoReconnectionEnabled = true
|
||||
builder.Settings.SmartSizing = true
|
||||
|
||||
Reference in New Issue
Block a user