Skip to content

Commit

Permalink
Allow insecure https urls (#3)
Browse files Browse the repository at this point in the history
* Allow insecure https urls

* some urls won't return json so don't error on this

* added some response code checks

* add response to trigger endpoint

* fix disable bug, added more tests
  • Loading branch information
alec-pinson authored Mar 25, 2023
1 parent 6b810a9 commit 34ab89f
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 181 deletions.
6 changes: 3 additions & 3 deletions cmd/terrarium-bot-v2/alert.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ func (a *Alert) isDisabled() bool {
if a.Disabled == 0 {
return false
}
if a.DisabledAt.Add(a.Disabled).After(time.Now()) {
return true
if a.DisabledAt.Add(a.Disabled).Before(time.Now()) {
return false
}
return false
return true
}
1 change: 1 addition & 0 deletions cmd/terrarium-bot-v2/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func (apiServer APIServer) Endpoint(w http.ResponseWriter, r *http.Request) {
// check if this is a trigger endpoint, if so do action
yes, t := isTriggerEndpoint(path)
if yes {
fmt.Fprintf(w, "ok")
t.doAction("Triggered by endpoint '" + path + "'")
}
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/terrarium-bot-v2/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Switch struct {
Id string `yaml:"id"`
On string `yaml:"on"`
Off string `yaml:"off"`
Insecure bool `yaml:"insecure"`
Status string // on/off
Disabled time.Duration
DisabledAt time.Time
Expand All @@ -57,6 +58,7 @@ type Switch struct {
type Sensor struct {
Id string `yaml:"id"`
Url string `yaml:"url"`
Insecure bool `yaml:"insecure"`
JsonPath string `yaml:"jsonPath"`
Unit string `yaml:"unit"`
Value int
Expand Down
282 changes: 128 additions & 154 deletions cmd/terrarium-bot-v2/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,192 +4,166 @@ import (
"os"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestLoad(t *testing.T) {
func TestLoadConfig(t *testing.T) {
// set up environment variables
os.Setenv("DEBUG", "true")
os.Setenv("DRY_RUN", "true")
os.Setenv("CONFIG_FILE", "test.yaml")
os.Setenv("NOTIFICATION_USER_TOKEN", "user123")
os.Setenv("NOTIFICATION_API_TOKEN", "api123")
os.Setenv("USE_IN_MEMORY_STATUS", "false")

// create test configuration
expectedConfig := Config{
Debug: true,
DryRun: true,
File: "test.yaml",
Day: StartAction{Start: "08:00", Action: []string{"do this", "then that"}},
Night: StartAction{Start: "22:00", Action: []string{"do that", "then this"}},
Sunrise: StartAction{Start: "06:00", Action: []string{"do something"}},
Sunset: StartAction{Start: "18:00", Action: []string{"do something else"}},
Trigger: []*Trigger{{Id: "tigger1", Sensor: "sensor1", Endpoint: "endpoint1", When: When{}, Action: []string{"do this"}}},
Switch: []*Switch{{Id: "switch1", On: "on", Off: "off"}},
Sensor: []*Sensor{{Id: "sensor1", Url: "http://sensor1.com", JsonPath: "path1", Unit: "unit1"}},
Notification: []*Notification{{
Id: "notif1",
AntiSpam: 10 * time.Minute,
Device: "device1",
UserToken: "NOTIFICATION_USER_TOKEN",
APIToken: "NOTIFICATION_API_TOKEN",
UserTokenValue: "",
APITokenValue: "",
LastNotification: time.Time{},
}},
Alert: []*Alert{{Sensor: "sensor1", When: When{}, After: 30 * time.Minute, Notification: []string{"notif1"}}},
UseInMemoryStatus: false,
}

// convert times
expectedConfig.Day.StartTime, _ = time.Parse("15:04", expectedConfig.Day.Start)
expectedConfig.Night.StartTime, _ = time.Parse("15:04", expectedConfig.Night.Start)
expectedConfig.Sunrise.StartTime, _ = time.Parse("15:04", expectedConfig.Sunrise.Start)
expectedConfig.Sunset.StartTime, _ = time.Parse("15:04", expectedConfig.Sunset.Start)
os.Setenv("USE_IN_MEMORY_STATUS", "true")

// create the test yaml file
data := `
configFileYaml := `
day:
start: 08:00
action:
- do this
- then that
start: "06:00"
action: ["doSomething"]
night:
start: 22:00
action:
- do that
- then this
start: "22:00"
action: ["doSomething"]
sunrise:
start: 06:00
action:
- do something
start: "06:22"
action: ["doSomething"]
sunset:
start: 18:00
action:
- do something else
start: "21:30"
action: ["doSomething"]
trigger:
- id: trigger1
sensor: sensor1
endpoint: endpoint1
- id: "trigger1"
sensor: "sensor1"
endpoint: "http://localhost:8080"
when:
day:
below: 50
above: 100
below: 5
night:
below: 20
above: 80
action:
- do this
else:
- do that
below: 5
action: ["doSomething"]
else: ["doSomethingElse"]
- id: "trigger2"
sensor: "sensor2"
endpoint: "http://anotherhost:8080"
when:
day:
above: 100
every: 10s
action: ["doSomething", "doSomethingElse"]
else: ["doSomethingElse", "doSomethingElseElse"]
switch:
- id: switch1
on: on
off: off
- id: "switch1"
on: "http://localhost:8081/on"
off: "http://localhost:8081/off"
insecure: true
- id: "switch2"
on: "http://localhost:8081/on"
off: "http://localhost:8081/off"
insecure: false
sensor:
- id: sensor1
url: http://sensor1.com
jsonPath: path1
unit: unit1
- id: "sensor1"
url: "http://localhost:8888"
jsonPath: "json.path"
unit: "unit"
- id: "sensor2"
url: "http://localhost:9999"
jsonPath: "json.path"
unit: "unit"
notification:
- id: notif1
antiSpam: 10m
device: device1
userToken: NOTIFICATION_USER_TOKEN
apiToken: NOTIFICATION_API_TOKEN
lastNotification: ""
- id: "notification1"
antiSpam: "30s"
device: "my_device"
userToken: "NOTIFICATION_USER_TOKEN"
apiToken: "NOTIFICATION_API_TOKEN"
alert:
- sensor: sensor1
- id: "alert1"
sensor: "sensor1"
when:
day:
below: 50
above: 100
below: 10
night:
below: 20
above: 80
after: 30m
notification:
- notif1
useInMemoryStatus: false`
err := os.WriteFile("test.yaml", []byte(data), 0644)
below: 5
after: "20m"
notification: ["notification1"]
useInMemoryStatus: true`
err := os.WriteFile("test.yaml", []byte(configFileYaml), 0644)
if err != nil {
t.Errorf("Error creating test.yaml: %v", err)
}

// load the configuration
loadedConfig := expectedConfig.Load()
loadedConfig := config.Load()

// ensure loaded configuration matches expected values
if loadedConfig.Debug != expectedConfig.Debug {
t.Errorf("Expected Debug %v, got %v", expectedConfig.Debug, loadedConfig.Debug)
}
if loadedConfig.DryRun != expectedConfig.DryRun {
t.Errorf("Expected DryRun %v, got %v", expectedConfig.DryRun, loadedConfig.DryRun)
}
if loadedConfig.File != expectedConfig.File {
t.Errorf("Expected File %v, got %v", expectedConfig.File, loadedConfig.File)
}
if loadedConfig.Day.Start != expectedConfig.Day.Start {
t.Errorf("Expected Day.Start %v, got %v", expectedConfig.Day.Start, loadedConfig.Day.Start)
}
if !loadedConfig.Day.StartTime.Equal(expectedConfig.Day.StartTime) {
t.Errorf("Expected Day.StartTime %v, got %v", expectedConfig.Day.StartTime, loadedConfig.Day.StartTime)
}
if len(loadedConfig.Day.Action) != len(expectedConfig.Day.Action) {
t.Errorf("Expected %v actions, got %v", len(expectedConfig.Day.Action), len(loadedConfig.Day.Action))
}
if loadedConfig.Night.Start != expectedConfig.Night.Start {
t.Errorf("Expected Night.Start %v, got %v", expectedConfig.Night.Start, loadedConfig.Night.Start)
}
if !loadedConfig.Night.StartTime.Equal(expectedConfig.Night.StartTime) {
t.Errorf("Expected Night.StartTime %v, got %v", expectedConfig.Night.StartTime, loadedConfig.Night.StartTime)
}
if len(loadedConfig.Night.Action) != len(expectedConfig.Night.Action) {
t.Errorf("Expected %v actions, got %v", len(expectedConfig.Night.Action), len(loadedConfig.Night.Action))
}
if loadedConfig.Sunrise.Start != expectedConfig.Sunrise.Start {
t.Errorf("Expected Sunrise.Start %v, got %v", expectedConfig.Sunrise.Start, loadedConfig.Sunrise.Start)
}
if !loadedConfig.Sunrise.StartTime.Equal(expectedConfig.Sunrise.StartTime) {
t.Errorf("Expected Sunrise.StartTime %v, got %v", expectedConfig.Sunrise.StartTime, loadedConfig.Sunrise.StartTime)
}
if len(loadedConfig.Sunrise.Action) != len(expectedConfig.Sunrise.Action) {
t.Errorf("Expected %v actions, got %v", len(expectedConfig.Sunrise.Action), len(loadedConfig.Sunrise.Action))
}
if loadedConfig.Sunset.Start != expectedConfig.Sunset.Start {
t.Errorf("Expected Sunset.Start %v, got %v", expectedConfig.Sunset.Start, loadedConfig.Sunset.Start)
}
if !loadedConfig.Sunset.StartTime.Equal(expectedConfig.Sunset.StartTime) {
t.Errorf("Expected Sunset.StartTime %v, got %v", expectedConfig.Sunset.StartTime, loadedConfig.Sunset.StartTime)
}
if len(loadedConfig.Sunset.Action) != len(expectedConfig.Sunset.Action) {
t.Errorf("Expected %v actions, got %v", len(expectedConfig.Sunset.Action), len(loadedConfig.Sunset.Action))
}
if len(loadedConfig.Trigger) != len(expectedConfig.Trigger) {
t.Errorf("Expected %v triggers, got %v", len(expectedConfig.Trigger), len(loadedConfig.Trigger))
}
if len(loadedConfig.Switch) != len(expectedConfig.Switch) {
t.Errorf("Expected %v switches, got %v", len(expectedConfig.Switch), len(loadedConfig.Switch))
}
if len(loadedConfig.Sensor) != len(expectedConfig.Sensor) {
t.Errorf("Expected %v sensors, got %v", len(expectedConfig.Sensor), len(loadedConfig.Sensor))
}
if len(loadedConfig.Notification) != len(expectedConfig.Notification) {
t.Errorf("Expected %v notifications, got %v", len(expectedConfig.Notification), len(loadedConfig.Notification))
}
if len(loadedConfig.Alert) != len(expectedConfig.Alert) {
t.Errorf("Expected %v alerts, got %v", len(expectedConfig.Alert), len(loadedConfig.Alert))
}
if loadedConfig.UseInMemoryStatus != expectedConfig.UseInMemoryStatus {
t.Errorf("Expected UseInMemoryStatus %v, got %v", expectedConfig.UseInMemoryStatus, loadedConfig.UseInMemoryStatus)
}
if loadedConfig.Notification[0].UserTokenValue != "user123" {
t.Errorf("Expected UserTokenValue %v, got %v", "user123", loadedConfig.Notification[0].UserTokenValue)
}
if loadedConfig.Notification[0].APITokenValue != "api123" {
t.Errorf("Expected APITokenValue %v, got %v", "api123", loadedConfig.Notification[0].APITokenValue)
}
assert.True(t, loadedConfig.Debug)
assert.True(t, loadedConfig.DryRun)
assert.Equal(t, "test.yaml", loadedConfig.File)

assert.Equal(t, "06:00", loadedConfig.Day.Start)
assert.Equal(t, []string{"doSomething"}, loadedConfig.Day.Action)
dayStartTime, err := time.Parse("15:04", "06:00")
assert.NoError(t, err)
assert.Equal(t, dayStartTime, loadedConfig.Day.StartTime)

assert.Equal(t, "22:00", loadedConfig.Night.Start)
assert.Equal(t, []string{"doSomething"}, loadedConfig.Night.Action)
nightStartTime, err := time.Parse("15:04", "22:00")
assert.NoError(t, err)
assert.Equal(t, nightStartTime, loadedConfig.Night.StartTime)

assert.Equal(t, "06:22", loadedConfig.Sunrise.Start)
assert.Equal(t, []string{"doSomething"}, loadedConfig.Sunrise.Action)
sunriseStartTime, err := time.Parse("15:04", "06:22")
assert.NoError(t, err)
assert.Equal(t, sunriseStartTime, loadedConfig.Sunrise.StartTime)

assert.Equal(t, "21:30", loadedConfig.Sunset.Start)
assert.Equal(t, []string{"doSomething"}, loadedConfig.Sunset.Action)
sunsetStartTime, err := time.Parse("15:04", "21:30")
assert.NoError(t, err)
assert.Equal(t, sunsetStartTime, loadedConfig.Sunset.StartTime)

assert.Len(t, loadedConfig.Trigger, 2)
assert.Equal(t, "trigger1", loadedConfig.Trigger[0].Id)
assert.Equal(t, "sensor1", loadedConfig.Trigger[0].Sensor)
assert.Equal(t, "http://localhost:8080", loadedConfig.Trigger[0].Endpoint)
assert.Equal(t, 5, loadedConfig.Trigger[0].When.Day.Below)
assert.Equal(t, 5, loadedConfig.Trigger[0].When.Night.Below)
assert.Equal(t, []string{"doSomething"}, loadedConfig.Trigger[0].Action)
assert.Equal(t, []string{"doSomethingElse"}, loadedConfig.Trigger[0].Else)

assert.Len(t, loadedConfig.Switch, 2)
assert.Equal(t, "switch1", loadedConfig.Switch[0].Id)
assert.Equal(t, "http://localhost:8081/on", loadedConfig.Switch[0].On)
assert.Equal(t, "http://localhost:8081/off", loadedConfig.Switch[0].Off)
assert.True(t, loadedConfig.Switch[0].Insecure)

assert.Len(t, loadedConfig.Sensor, 2)
assert.Equal(t, "sensor1", loadedConfig.Sensor[0].Id)
assert.Equal(t, "http://localhost:8888", loadedConfig.Sensor[0].Url)
assert.False(t, loadedConfig.Sensor[0].Insecure)
assert.Equal(t, "json.path", loadedConfig.Sensor[0].JsonPath)
assert.Equal(t, "unit", loadedConfig.Sensor[0].Unit)

assert.Len(t, loadedConfig.Notification, 1)
assert.Equal(t, "notification1", loadedConfig.Notification[0].Id)
assert.Equal(t, 30*time.Second, loadedConfig.Notification[0].AntiSpam)
assert.Equal(t, "my_device", loadedConfig.Notification[0].Device)
assert.Equal(t, "NOTIFICATION_USER_TOKEN", loadedConfig.Notification[0].UserToken)
assert.Equal(t, "NOTIFICATION_API_TOKEN", loadedConfig.Notification[0].APIToken)
assert.Equal(t, "user123", loadedConfig.Notification[0].UserTokenValue)
assert.Equal(t, "api123", loadedConfig.Notification[0].APITokenValue)

assert.Len(t, loadedConfig.Alert, 1)
assert.Equal(t, "alert1", loadedConfig.Alert[0].Id)
assert.Equal(t, "sensor1", loadedConfig.Alert[0].Sensor)
assert.Equal(t, 10, loadedConfig.Alert[0].When.Day.Below)
assert.Equal(t, 5, loadedConfig.Alert[0].When.Night.Below)
assert.Equal(t, 20*time.Minute, loadedConfig.Alert[0].After)
assert.Equal(t, []string{"notification1"}, loadedConfig.Alert[0].Notification)

assert.True(t, loadedConfig.UseInMemoryStatus)

// clean up test files
// clean up
os.Remove("test.yaml")
}
4 changes: 4 additions & 0 deletions cmd/terrarium-bot-v2/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ sunset:
start: "20:55"
action:
- switch.big_led.off
- alert.temperature.disable.1h # disable temperature alert for 1 hour (allow to settle from day to night temps)

trigger:
- id: heating
Expand Down Expand Up @@ -115,12 +116,15 @@ switch:
- id: camera-night-vision-1
on: https://root:${CAMERA_PASSWORD}@dafang/cgi-bin/action.cgi?cmd=toggle-rtsp-nightvision-on
off: https://root:${CAMERA_PASSWORD}@dafang/cgi-bin/action.cgi?cmd=toggle-rtsp-nightvision-off
insecure: true # ignore ssl certificate
- id: camera-night-vision-2
on: https://root:${CAMERA_PASSWORD}@dafang/cgi-bin/action.cgi?cmd=ir_led_on
off: https://root:${CAMERA_PASSWORD}@dafang/cgi-bin/action.cgi?cmd=ir_led_off
insecure: true # ignore ssl certificate
- id: camera-night-vision-3
on: https://root:${CAMERA_PASSWORD}@dafang/cgi-bin/action.cgi?cmd=ir_cut_off
off: https://root:${CAMERA_PASSWORD}@dafang/cgi-bin/action.cgi?cmd=ir_cut_on
insecure: true # ignore ssl certificate

sensor:
# - id: temperature
Expand Down
Loading

0 comments on commit 34ab89f

Please sign in to comment.