Finalize rdp templating

This commit is contained in:
Bolke de Bruin
2023-05-15 10:41:35 +02:00
parent cdc497f365
commit 6b32631434
13 changed files with 128 additions and 44 deletions

View 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
}

View 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)
})
}
}

View File

@@ -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)

View File

@@ -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