Browse Source

Initial wifi integration (#7)

Wifi Integration

Clean up

Fix removing only started workers on update

Set default gateway via tenus lib

Introduce BaseWorker type

and changed the way a worker is killed or turned off

Fix wifi frontend and add missing i18n en

Use channels for worker orchestrating

AP/STA mode working

we have to fix

* on initial creation AP has a client network (needs a dhcp and dns server)
* restarting/reloading the worker properly

Set wifi card link up before scanning

Delete/reset network interfaces on confd clean-up

Split wifi into STA and AP worker

create virtual network interfaces in confd

Serve watcher results via API

Save watcher results to database

Add test function to worker interface

Add wireless station frontend page

Implement wifi scanner and api handler

4.   make it possible to scan for networks

Initial wifi integration

1.   make it possible to configure and start hostapd
2.   make it possible to configure and start wpa_supplicant
3.   make it possible to use both (wpa_supplicant and hostapd)
3.1. iw dev wlp5s0 interface add wlp5s0_XX type managed address aa:bb:cc:dd:ee:XX
3.2. (main device must be down) ip link set dev wlp5s0 down
3.3. order matters. start hostapd first!

Co-authored-by: Lukas Matt <lukas@matt.wf>
Reviewed-on: #7
master
zauberstuhl 9 months ago
parent
commit
0bc30a877b
45 changed files with 2583 additions and 995 deletions
  1. +3
    -0
      config/app.json.example
  2. +3
    -0
      config/init.go
  3. +10
    -0
      db/migrations/000055_create_watcher_result_table.up.sql
  4. +4
    -0
      db/migrations/000056_alter_networks_table.up.sql
  5. +1
    -0
      go.mod
  6. +100
    -0
      go.sum
  7. +6
    -1
      handler/init.go
  8. +27
    -14
      handler/system.go
  9. +131
    -0
      handler/system_wifi.go
  10. +94
    -0
      handler/system_worker.go
  11. +96
    -0
      helper/worker.go
  12. +2
    -0
      init.go
  13. +71
    -0
      log.go
  14. +10
    -0
      model/dns_record.go
  15. +10
    -0
      model/network.go
  16. +22
    -43
      model/network_interface.go
  17. +128
    -0
      model/watcher_result.go
  18. +27
    -12
      server.go
  19. +67
    -47
      src/assets/images/logo.svg
  20. +0
    -137
      src/components/AccessPoint.vue
  21. +3
    -2
      src/components/EmptyState.vue
  22. +11
    -2
      src/components/Navigation.vue
  23. +86
    -0
      src/components/wireless/AccessPoint.vue
  24. +276
    -0
      src/components/wireless/Station.vue
  25. +40
    -19
      src/i18n/messages/en.js
  26. +10
    -4
      src/router/index.js
  27. +26
    -0
      types/color.go
  28. +35
    -0
      types/log.go
  29. +24
    -12
      types/model_configuration.go
  30. +199
    -25
      types/worker.go
  31. +217
    -196
      worker/confd.go
  32. +59
    -21
      worker/dhcp_client.go
  33. +97
    -219
      worker/dhcp_server.go
  34. +18
    -52
      worker/dns.go
  35. +9
    -20
      worker/frontend.go
  36. +8
    -20
      worker/hw_detect.go
  37. +37
    -1
      worker/init.go
  38. +8
    -20
      worker/iptable.go
  39. +11
    -21
      worker/nfq.go
  40. +10
    -20
      worker/portal.go
  41. +9
    -20
      worker/profiler.go
  42. +179
    -67
      worker/watcher.go
  43. +222
    -0
      worker/wifi_ap.go
  44. +174
    -0
      worker/wifi_sta.go
  45. +3
    -0
      workers.go

+ 3
- 0
config/app.json.example View File

@@ -20,5 +20,8 @@
},
"session": {
"secret": "__change_secret_value_to_random_string__"
},
"sentry": {
"dsn": ""
}
}

+ 3
- 0
config/init.go View File

@@ -33,6 +33,9 @@ type Config struct {
Session struct {
Secret string `json:"secret"`
} `json:"session"`
Sentry struct {
DSN string `json:"dsn"`
} `json:"sentry"`
Confd map[string]interface{} `json:"confd"`
}



+ 10
- 0
db/migrations/000055_create_watcher_result_table.up.sql View File

@@ -0,0 +1,10 @@
create table watcher_results (
id serial primary key,
created_at timestamp not null,
updated_at timestamp not null,
worker_name text not null,
alive boolean not null,
retries int not null,
error text
);
create unique index watcher_results_index_on_worker_name on watcher_results(worker_name);

+ 4
- 0
db/migrations/000056_alter_networks_table.up.sql View File

@@ -0,0 +1,4 @@
drop index networks_network;
alter table networks drop constraint check_dhcp_dns_and_client_relation;
alter table network_interfaces add column gateway_id int default null,
add constraint network_interfaces_gateway_id_fkey foreign key (gateway_id) references networks(id);

+ 1
- 0
go.mod View File

@@ -8,6 +8,7 @@ require (
github.com/coreos/go-iptables v0.4.5
github.com/drewlanenga/govector v0.0.0-20160727150047-f69e9f02317e // indirect
github.com/fsnotify/fsnotify v1.4.9
github.com/getsentry/sentry-go v0.10.0 // indirect
github.com/gin-contrib/logger v0.0.2
github.com/gin-contrib/pprof v1.2.1
github.com/gin-contrib/sessions v0.0.3


+ 100
- 0
go.sum View File

@@ -16,25 +16,33 @@ git.feneas.org/fengg/go-nfqueue v1.1.1-0.20200411120219-af6ba54ed32b h1:BsqGlBVg
git.feneas.org/fengg/go-nfqueue v1.1.1-0.20200411120219-af6ba54ed32b/go.mod h1:nwfTIdBji51L/XmQ19NTGjwRad/NxZJTwNSkUbBYnmc=
git.feneas.org/fengg/goprotoident v1.20200421.0 h1:ZDuooIK/aDRcW6mfqVU7Xs5Id2ApDb6kEmzt5eYColI=
git.feneas.org/fengg/goprotoident v1.20200421.0/go.mod h1:zF5F26Ra+hid0lHtIM82Rh2N3fNw0l6vfXashjqGF6k=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
@@ -55,18 +63,23 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/containerd/containerd v1.2.7 h1:8lqLbl7u1j3MmiL9cJ/O275crSq7bfwUayvvatEupQk=
github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/coredhcp/coredhcp v0.0.0-20200809170558-a9aa31766d13 h1:jkgvfRqS0lCZtdmdrszcpTl7RgFjjHbwVEyhhckGSq8=
github.com/coredhcp/coredhcp v0.0.0-20200809170558-a9aa31766d13/go.mod h1:HngrsN3zIxGgQaRrCb2GyQq9xLK/ehi6r53/nbJM8qo=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc=
@@ -81,7 +94,9 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dhui/dktest v0.3.0 h1:kwX5a7EkLcjo7VpsPQSYJcKGbXBXdjI9FGjuUj1jn6I=
github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
@@ -98,18 +113,26 @@ github.com/docker/libcontainer v2.2.1+incompatible h1:++SbbkCw+X8vAd4j2gOCzZ2Nn7
github.com/docker/libcontainer v2.2.1+incompatible/go.mod h1:osvj61pYsqhNCMLGX31xr7klUBhHb/ZBuXS0o1Fvwbw=
github.com/drewlanenga/govector v0.0.0-20160727150047-f69e9f02317e h1:H+R6TS5huNAykR6HMHmY7lqrgEfnyWgm7Ynn38BSBLw=
github.com/drewlanenga/govector v0.0.0-20160727150047-f69e9f02317e/go.mod h1:AbP/uRrjZFATEwl0P2DHePteIMZRWHEJBWBmMmLdCkk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/getsentry/sentry-go v0.10.0 h1:6gwY+66NHKqyZrdi6O2jGdo7wGdo9b3B69E01NFgT5g=
github.com/getsentry/sentry-go v0.10.0/go.mod h1:kELm/9iCblqUYh+ZRML7PNdCvEuw24wBvJPYyi86cws=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/logger v0.0.2 h1:qT6qOR9/mp9hrHAgTEVxpjvS3anQtiUTtzJhf+NlBQM=
github.com/gin-contrib/logger v0.0.2/go.mod h1:Eca5g93bobBwWSNeuLdTqRvNK6btb3XSHdU9ePZ+toM=
@@ -126,10 +149,13 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
@@ -138,6 +164,9 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -165,6 +194,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -196,6 +226,7 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU=
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -215,6 +246,7 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -226,10 +258,17 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/insomniacslk/dhcp v0.0.0-20200621044212-d74cd86ad5b8 h1:u+vle+5E78+cT/CSMD5/Y3NUpMgA83Yu2KhG+Zbco/k=
github.com/insomniacslk/dhcp v0.0.0-20200621044212-d74cd86ad5b8/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
github.com/insomniacslk/dhcp v0.0.0-20201112113307-4de412bc85d8 h1:R1oP0/QEyvaL7dm+mBQouQ9V1X6gqQr5taZA1yaq5zQ=
github.com/insomniacslk/dhcp v0.0.0-20201112113307-4de412bc85d8/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI=
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -244,14 +283,24 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -262,6 +311,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -269,13 +320,16 @@ github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lytics/anomalyzer v0.0.0-20151102000650-13cee1061701 h1:liUjIx6L9ZQ/Ilt4c7CZ1sd4zDv2X9R+uw01evYA8o0=
github.com/lytics/anomalyzer v0.0.0-20151102000650-13cee1061701/go.mod h1:zuQaM4YroHR9LIvA+FNOoy2VQTSxFvNrAcqeVXRoUyU=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
@@ -283,6 +337,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE=
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
@@ -295,15 +350,18 @@ github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZ
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 h1:aFkJ6lx4FPip+S+Uw4aTegFMct9shDvP+79PsSxpm3w=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/milosgajdos/tenus v0.0.3 h1:jmaJzwaY1DUyYVD0lM4U+uvP2kkEg1VahDqRFxIkVBE=
github.com/milosgajdos/tenus v0.0.3/go.mod h1:eIjx29vNeDOYWJuCnaHY2r4fq5egetV26ry3on7p8qY=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
@@ -318,12 +376,18 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -352,6 +416,7 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -382,12 +447,17 @@ github.com/rs/zerolog v1.16.0 h1:AaELmZdcJHT8m6oZ5py4213cdFK8XGXkB3dFdAQ+P7Q=
github.com/rs/zerolog v1.16.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sajari/regression v1.0.1 h1:iTVc6ZACGCkoXC+8NdqH5tIreslDTT/bXxT6OmHR5PE=
github.com/sajari/regression v1.0.1/go.mod h1:NeG/XTW1lYfGY7YV/Z0nYDV/RGh3wxwd1yW46835flM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@@ -402,10 +472,12 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -426,15 +498,29 @@ github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/R
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -447,12 +533,15 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -490,6 +579,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -502,6 +592,7 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a h1:+HHJiFUXVOIS9mr1ThqkQD1N8vpFCfCShqADBM12KTc=
golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
@@ -519,6 +610,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -527,6 +619,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -542,6 +635,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -577,12 +671,14 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@@ -597,6 +693,7 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.7.0 h1:Hdks0L0hgznZLG9nzXb8vZ0rRvqNvAcgAp84y7Mwkgw=
@@ -654,6 +751,8 @@ gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWd
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
@@ -663,6 +762,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=


+ 6
- 1
handler/init.go View File

@@ -17,15 +17,20 @@ package handler
//
import (
"os"
"time"
"net/http"

"tea.fen.gg/fengg/server/types"
"tea.fen.gg/fengg/server/helper"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog"
"github.com/patrickmn/go-cache"
)

var logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout, NoColor: true})
var (
logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout, NoColor: true})
handlerCache = cache.New(10 * time.Second, 30 * time.Second)
)

func Logger(customLogger zerolog.Logger) {
logger = customLogger.With().Str("package", "handler").Logger()


+ 27
- 14
handler/system.go View File

@@ -248,10 +248,6 @@ func settingsGETHandler(ctx *gin.Context, key types.ConfigurationKey) {
helper.HandlerJsonError(fmt.Sprintf("%s configuration key does not exist", key), err, ctx)
}

func SettingsAPGETHandler(ctx *gin.Context) {
settingsGETHandler(ctx, types.AccessPointConfiguration)
}

func SettingsWLGETHandler(ctx *gin.Context) {
settingsGETHandler(ctx, types.WhiteListConfiguration)
}
@@ -260,6 +256,14 @@ func SettingsPTLGETHandler(ctx *gin.Context) {
settingsGETHandler(ctx, types.PortalConfiguration)
}

func SettingsWifiSTAGETHandler(ctx *gin.Context) {
settingsGETHandler(ctx, types.WifiSTAConfiguration)
}

func SettingsWifiAPGETHandler(ctx *gin.Context) {
settingsGETHandler(ctx, types.WifiAPConfiguration)
}

/**
* @api {post} /system/settings/:type Update system settings configuration
* @apiVersion 1.0.0
@@ -333,10 +337,6 @@ func settingsPOSTHandler(ctx *gin.Context, key types.ConfigurationKey, data type
}
}

func SettingsAPPOSTHandler(ctx *gin.Context) {
settingsPOSTHandler(ctx, types.AccessPointConfiguration, &types.ConfigurationAccessPointData{})
}

func SettingsWLPOSTHandler(ctx *gin.Context) {
settingsPOSTHandler(ctx, types.WhiteListConfiguration, &types.ConfigurationWhiteListData{})
}
@@ -345,6 +345,14 @@ func SettingsPTLPOSTHandler(ctx *gin.Context) {
settingsPOSTHandler(ctx, types.PortalConfiguration, &types.ConfigurationPortalData{})
}

func SettingsWifiSTAPOSTHandler(ctx *gin.Context) {
settingsPOSTHandler(ctx, types.WifiSTAConfiguration, &types.ConfigurationWifiData{})
}

func SettingsWifiAPPOSTHandler(ctx *gin.Context) {
settingsPOSTHandler(ctx, types.WifiAPConfiguration, &types.ConfigurationWifiData{})
}

/**
* @api {get} /system/settings/bearer Fetch all tokens related to the user account
* @apiVersion 1.0.0
@@ -459,7 +467,7 @@ func BearerDELETEHandler(ctx *gin.Context) {
}

ctx.JSON(http.StatusOK,types.HandlerJSONResponse{
Type:types.HandlerSuccessType,
Type: types.HandlerSuccessType,
})
}

@@ -523,7 +531,7 @@ func InterfacesGETHandler(ctx *gin.Context) {
}

ctx.JSON(http.StatusOK,types.HandlerJSONResponse{
Type:types.HandlerSuccessType,
Type: types.HandlerSuccessType,
Data: interfaces,
})
}
@@ -539,6 +547,11 @@ func InterfacesPOSTHandler(ctx *gin.Context) {
// trigger confd to apply new configuration parameters
go func() {
worker.ConfigChannel(types.NetworkConfiguration)
if networkInterface.DefaultGateway {
// this triggeres the DHCP clients which are responsible
// for creating the correct routes
worker.ConfigChannel(types.NetworkDHCPClientConfiguration)
}
}()
}
} else {
@@ -547,7 +560,7 @@ func InterfacesPOSTHandler(ctx *gin.Context) {
}

ctx.JSON(http.StatusOK,types.HandlerJSONResponse{
Type:types.HandlerSuccessType,
Type: types.HandlerSuccessType,
})
}

@@ -613,7 +626,7 @@ func NetworksGETHandler(ctx *gin.Context) {
}

ctx.JSON(http.StatusOK,types.HandlerJSONResponse{
Type:types.HandlerSuccessType,
Type: types.HandlerSuccessType,
Data: networks,
})
}
@@ -632,7 +645,7 @@ func NetworksPOSTHandler(ctx *gin.Context) {
}

ctx.JSON(http.StatusOK,types.HandlerJSONResponse{
Type:types.HandlerSuccessType,
Type: types.HandlerSuccessType,
})
}

@@ -650,7 +663,7 @@ func NetworksDELETEHandler(ctx *gin.Context) {
helper.HandlerJsonError("cannot delete network object", err, ctx)
} else {
ctx.JSON(http.StatusOK,types.HandlerJSONResponse{
Type:types.HandlerSuccessType,
Type: types.HandlerSuccessType,
})
}
}

+ 131
- 0
handler/system_wifi.go View File

@@ -0,0 +1,131 @@
package handler
//
// Fengg Security Gateway Server Application
// Copyright (C) 2020 Lukas Matt <support@fen.gg>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

import (
"net/http"
"strings"
"time"

"tea.fen.gg/fengg/server/types"
"tea.fen.gg/fengg/server/helper"
"tea.fen.gg/fengg/server/model"
"github.com/gin-gonic/gin"
)

/**
* @api {get} /system/wifi/scan Scan for available wifi networks
* @apiVersion 1.0.0
* @apiName WifiScanHandler
* @apiGroup system
* @apiPermission user
* @apiDescription <div class="alert alert-danger">Please note that the results are being cached for a couple of seconds.</div>
*
* @apiExample Usage (curl):
* curl -s http://localhost:8080/api/v1/system/wifi/scan
*
* @apiSuccess {String} type Will be set to <code>success</code>.
* @apiSuccess {Object[]} data List of available wifi networks
* @apiSuccess {String} data.ssid The service set ID of the wifi network
* @apiSuccess {Number} data.dBm The signal strength in dBm
* @apiSuccess {Number} data.quality The signal strength in percentage
*
* @apiSuccessExample Response
* HTTP/1.1. 200 OK
* {
* "type":"success",
* "data":[
* {
* "ssid":"ZauberNet",
* "dBm":-72,
* "quality":56
* }
* ]
* }
*
* @apiError {String} type Will be set to <code>error</code>.
* @apiError {String} msg Contains more details about the error itself.
*
* @apiErrorExample Authentication error
* HTTP/1.1 403 Forbidden
* {
* "type": "error",
* "msg": "no user found for session"
* }
*
* @apiErrorExample Server error
* HTTP/1.1 500 Internal Server Error
* {
* "type": "error",
* "msg": "too many connections"
* }
*/
func WifiScanHandler(ctx *gin.Context) {
type prettyPrint struct{
SSID string `json:"ssid"`
DBM float64 `json:"dBm"`
Quality int `json:"quality"`
}

var result []prettyPrint
if resultInt, ok := handlerCache.Get("WifiScanHandler"); ok {
result, _ = resultInt.([]prettyPrint)
} else {
var networkInterfaces model.NetworkInterfaces
err := networkInterfaces.FindWirelessCards()
if err != nil || len(networkInterfaces) < 1 {
helper.HandlerJsonError("cannot find wireless network interface", err, ctx)
return
}

var iface string
if len(networkInterfaces) > 1 {
for _, intf := range networkInterfaces {
if strings.HasSuffix(intf.Name, "_sta") {
iface = intf.Name
break
}
}
}
// fallback
if iface == "" {
iface = networkInterfaces[0].Name
}

// XXX in case of multiple wifi cards let the user choose which one to use
ssids, err := helper.ScanWifiNetworks(iface)
if err != nil {
helper.HandlerJsonError("cannot scan wifi networks", err, ctx)
return
}

for key, value := range ssids {
result = append(result, prettyPrint{
SSID: key,
DBM: value,
Quality: int(2 * (value + 100)),
})
}

handlerCache.Set("WifiScanHandler", result, 10 * time.Second)
}

ctx.JSON(http.StatusOK,types.HandlerJSONResponse{
Type: types.HandlerSuccessType,
Data: result,
})
}

+ 94
- 0
handler/system_worker.go View File

@@ -0,0 +1,94 @@
package handler
//
// Fengg Security Gateway Server Application
// Copyright (C) 2020 Lukas Matt <support@fen.gg>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

import (
"net/http"

"tea.fen.gg/fengg/server/types"
"tea.fen.gg/fengg/server/helper"
"tea.fen.gg/fengg/server/model"
"github.com/gin-gonic/gin"
)

/**
* @api {get} /system/worker/info Fetch worker status information
* @apiVersion 1.0.0
* @apiName WorkerInfoHandler
* @apiGroup system
* @apiPermission user
*
* @apiExample Usage (curl):
* curl -s http://localhost:8080/api/v1/system/worker/info
*
* @apiSuccess {String} type Will be set to <code>success</code>.
* @apiSuccess {Object[]} data List of available wifi networks
* @apiSuccess {Number} data.id Database identifier
* @apiSuccess {Date} data.createdAt Database creation timestamp
* @apiSuccess {Date} data.updatedAt Database update timestamp
* @apiSuccess {String} data.workerName The worker name in string format
* @apiSuccess {Boolean} data.alive If the worker is currently running
* @apiSuccess {Number} data.retries How often the worker restarted
* @apiSuccess {String} data.error Error message if the worker failed or encountered a problem
*
* @apiSuccessExample Response
* HTTP/1.1. 200 OK
* {
* "type":"success",
* "data":[
* {
* "id":8,
* "createdAt":"2021-01-28T15:42:10.765771Z",
* "updatedAt":"2021-01-28T16:03:00.079666Z",
* "workerName":"Frontend",
* "alive":true,
* "retries":0,
* "error":""
* }
* ]
* }
*
* @apiError {String} type Will be set to <code>error</code>.
* @apiError {String} msg Contains more details about the error itself.
*
* @apiErrorExample Authentication error
* HTTP/1.1 403 Forbidden
* {
* "type": "error",
* "msg": "no user found for session"
* }
*
* @apiErrorExample Server error
* HTTP/1.1 500 Internal Server Error
* {
* "type": "error",
* "msg": "too many connections"
* }
*/
func WorkerInfoHandler(ctx *gin.Context) {
var result model.WatcherResults
err := result.FindAll()
if err != nil {
helper.HandlerJsonError("cannot fetch worker results from database", err, ctx)
return
}

ctx.JSON(http.StatusOK,types.HandlerJSONResponse{
Type: types.HandlerSuccessType,
Data: result,
})
}

+ 96
- 0
helper/worker.go View File

@@ -0,0 +1,96 @@
package helper
//
// Fengg Security Gateway Server Application
// Copyright (C) 2021 Lukas Matt <support@fen.gg>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
import (
"regexp"
"os/exec"
"strconv"
"bytes"
"crypto/rand"
"fmt"

"github.com/milosgajdos/tenus"
)

func RandomMac(unicast bool) (string, error) {
buf := make([]byte, 6)
_, err := rand.Read(buf)
if err != nil {
return "", err
}

// set local and unicast/multicast bit
if unicast {
buf[0] = buf[0] << 2
buf[0] |= 2
} else {
buf[0] |= 3
}

return fmt.Sprintf(
"%02x:%02x:%02x:%02x:%02x:%02x",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
), nil
}

func ScanWifiNetworks(intfName string) (ssid map[string]float64, err error) {
ssid = make(map[string]float64)
// lookup the cli tool
path, err := exec.LookPath("iw")
if err != nil {
return ssid, err
}
// set link up
link, err := tenus.NewLinkFrom(intfName)
if err != nil {
return ssid, err
}
err = link.SetLinkUp()
if err != nil {
return ssid, err
}
// start scanning on the given interface
out, err := exec.Command(path, "dev", intfName, "scan").Output()
if err != nil {
return ssid, err
}
// parse the log output of iw and fetch SSID and signal strength
var tempDBM float64
ssidRegex := regexp.MustCompile(`^\s*SSID: (.+?)$`)
dbmRegex := regexp.MustCompile(`^\s*signal: ([0-9\-\.]+?) dBm$`)
lines := bytes.Split(out, []byte{0x0a}) // split newline
for _, line := range lines {
// dBm is the signal strength and can be transformed into percentage as following:
//
// quality = 2 * (dBm + 100) where dBm: [-100 to -50]
// dBm = (quality / 2) - 100 where quality: [0 to 100]
if res := dbmRegex.FindAllSubmatch(line, 1); len(res) > 0 && len(res[0]) == 2 {
tempDBM, err = strconv.ParseFloat(string(res[0][1]), 64)
if err != nil {
logger.Debug().Err(err).Msg("cannot parse signal strength")
tempDBM = -100.0
}
continue
}

if res := ssidRegex.FindAllSubmatch(line, 1); len(res) > 0 && len(res[0]) == 2 {
ssid[string(res[0][1])] = tempDBM
continue
}
}
return ssid, nil
}

+ 2
- 0
init.go View File

@@ -21,6 +21,7 @@ import (
"tea.fen.gg/fengg/server/config"
"tea.fen.gg/fengg/server/model"
"tea.fen.gg/fengg/server/helper"
"tea.fen.gg/fengg/server/handler"
"tea.fen.gg/fengg/server/netfilter"
"tea.fen.gg/fengg/server/types"
"tea.fen.gg/fengg/server/worker"
@@ -33,6 +34,7 @@ import (
func init() {
// setup module logging
helper.Logger(logger)
handler.Logger(logger)
model.Logger(logger)
netfilter.Logger(logger)
types.Logger(logger)


+ 71
- 0
log.go View File

@@ -0,0 +1,71 @@
package main
//
// Fengg Security Gateway Server Application
// Copyright (C) 2020 Lukas Matt <support@fen.gg>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

import (
"os"
"regexp"
"strings"

"tea.fen.gg/fengg/server/types"
"github.com/rs/zerolog"
)

var callerRegex = regexp.MustCompile(`^(.+?)/(fengg|\.golang|go)/`)

func formatCaller(in interface{}) string {
var out strings.Builder
inString, ok := in.(string)
if !ok {
return "<nil>"
}
outPath := callerRegex.ReplaceAllString(inString, "")
out.WriteString(types.ColorCyan)
out.WriteString(outPath)
out.WriteString(types.ColorReset)
out.WriteString(" >")
return out.String()
}

func formatMessage(in interface{}) string {
inString, ok := in.(string)
if !ok {
return "<nil>"
}
return strings.ReplaceAll(inString, "\n", "\n> ")
}

var consoleWriter = zerolog.ConsoleWriter{
Out: os.Stdout,
PartsOrder: []string{
zerolog.TimestampFieldName,
zerolog.LevelFieldName,
zerolog.CallerFieldName,
zerolog.MessageFieldName,
},
FormatCaller: formatCaller,
FormatMessage: formatMessage,
}

var logger = zerolog.New(os.Stdout).
Output(consoleWriter).
Hook(types.SentryLogHook{}).
With().
Stack().
Caller().
Timestamp().
Logger()

+ 10
- 0
model/dns_record.go View File

@@ -133,6 +133,16 @@ func (record *DnsRecord) Create() error {
return nil
}

func (records *DnsRecords) FindAll() error {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {
return err
}
defer db.Close()

return db.Select(records, fmt.Sprintf(DnsRecordQueryTmpl, ""))
}

func (records *DnsRecords) FindByNetworkID(id uint) error {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {


+ 10
- 0
model/network.go View File

@@ -139,3 +139,13 @@ func (networks *Networks) FindAll() error {

return db.Select(networks, fmt.Sprintf(NetworkQueryTmpl, ""))
}

func (networks *Networks) FindAllDHCP() error {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {
return err
}
defer db.Close()

return db.Select(networks, fmt.Sprintf(NetworkQueryTmpl, "WHERE dhcp = true"))
}

+ 22
- 43
model/network_interface.go View File

@@ -28,17 +28,17 @@ const (
NetworkInterfaceNamedInsertTmpl = `
INSERT INTO network_interfaces (
created_at, updated_at, name, network_id, wireless, physical,
bridge_master, bridge_id, tun, default_gateway, link
bridge_master, bridge_id, tun, default_gateway, gateway_id, link
) VALUES (
now(), now(), :name, :network_id, :wireless, :physical,
:bridge_master, :bridge_id, :tun, false, :link
now(), now(), :name, :network_id, :wireless, :physical, :bridge_master,
:bridge_id, :tun, :default_gateway, :gateway_id, :link
) RETURNING id;`

NetworkInterfaceNamedUpdateTmpl = `
UPDATE network_interfaces
SET updated_at=now(), network_id=:network_id, default_gateway=:default_gateway,
wireless=:wireless, physical=:physical, bridge_master=:bridge_master,
bridge_id=:bridge_id, tun=:tun, link=:link
gateway_id=:gateway_id, wireless=:wireless, physical=:physical,
bridge_master=:bridge_master, bridge_id=:bridge_id, tun=:tun, link=:link
WHERE name=:name OR id=:id;`

NetworkInterfaceNamedDeleteTmpl = `DELETE FROM network_interfaces WHERE %s;`
@@ -53,6 +53,7 @@ type NetworkInterface struct {

Name string `db:"name" json:"name"`
DefaultGateway bool `db:"default_gateway" json:"defaultGateway"`
GatewayID *uint `db:"gateway_id" json:"gatewayId,omitempty"`
NetworkID uint `db:"network_id" json:"networkId" binding="required"`
WirelessCard bool `db:"wireless" json:"wirelessCard"`
PhysicalCard bool `db:"physical" json:"physicalCard"`
@@ -82,44 +83,10 @@ func (intfs *NetworkInterfaces) FindByNetworkID(id uint) error {
return db.Select(intfs, fmt.Sprintf(NetworkInterfaceQueryTmpl, "WHERE network_id=$1"), id)
}

// BridgeMasterInterface will return nil if the interface is not part of a bridge
// or the lookup failed. If successful it will return the master network interface
func (intf *NetworkInterface) BridgeMasterInterface() *NetworkInterface {
// Return if this interface is not part of a birdge setup
if intf.BridgeID == nil {
return nil
}
// Return itself if it has the master role
if intf.BridgeMaster {
return intf
}
// Lookup the master interface
var masterIntf NetworkInterface
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {
logger.Error().Err(err).Msg("cannot open database")
return nil
}
defer db.Close()

err = db.Get(&masterIntf, fmt.Sprintf(
NetworkInterfaceQueryTmpl,
"WHERE bridge_master=true AND bridge_id=$1",
), intf.BridgeID)

if err != nil {
logger.Debug().Err(err).Msg("cannot find master bridge interface")
return nil
}
return &masterIntf
}

// ResetBridgeSetup will remove all bridge related flags from the
// master and salve interfaces. This function can only be used on
// the master interface itself ((struct).BridgeMaster).
// ResetBridgeSetup will remove all bridge related flags from the master and salve interfaces.
func (intf *NetworkInterface) ResetBridgeSetup() error {
if !intf.BridgeMaster || intf.BridgeID == nil {
return errors.New("the network interface is not the bridge master")
if intf.BridgeID == nil {
return errors.New("cannot reset bridge without the bridge_id")
}

db, err := sqlx.Connect(dbDriver, dbConnect)
@@ -172,7 +139,9 @@ func (intf *NetworkInterface) Update() error {

if intf.DefaultGateway {
// only one interface can act as gateway (WAN)
_, err = db.Exec(`UPDATE network_interfaces SET default_gateway=false;`)
_, err = db.Exec(`
UPDATE network_interfaces
SET default_gateway=false and gateway_id=null;`)
if err != nil {
return err
}
@@ -216,6 +185,16 @@ func (intf *NetworkInterface) Create() error {
return nil
}

func (intfs *NetworkInterfaces) FindWirelessCards() error {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {
return err
}
defer db.Close()

return db.Select(intfs, fmt.Sprintf(NetworkInterfaceQueryTmpl, "WHERE wireless = true"))
}

func (intfs *NetworkInterfaces) FindAll() error {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {


+ 128
- 0
model/watcher_result.go View File

@@ -0,0 +1,128 @@
package model
//
// Fengg Security Gateway Server Application
// Copyright (C) 2020 Lukas Matt <support@fen.gg>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
import (
"time"
"fmt"

"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
)

const (
WatcherResultNamedInsertTmpl = `
INSERT INTO watcher_results (
created_at, updated_at, worker_name, alive, retries, error
) VALUES (
now(), now(), :worker_name, :alive, :retries, :error
) RETURNING id;`

WatcherResultNamedUpdateTmpl = `
UPDATE watcher_results
SET updated_at=now(), alive=:alive, retries=:retries, error=:error
WHERE id=:id
OR worker_name=:worker_name;`

WatcherResultResetRetriesTmpl = `UPDATE watcher_results SET retries=0 WHERE retries > 0;`

WatcherResultQueryTmpl = `SELECT * FROM watcher_results %s;`
)

type WatcherResult struct {
ID uint `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"createdAt"`
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`

WorkerName string `db:"worker_name" json:"workerName"`
Alive bool `db:"alive" json:"alive"`
Retries int `db:"retries" json:"retries"`
Error *string `db:"error" json:"error,omitempty"`
}

type WatcherResults []WatcherResult

func NewWatcherResult() *WatcherResult {
return &WatcherResult{CreatedAt: time.Now()}
}

func (results *WatcherResults) FindAll() error {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {
return err
}
defer db.Close()

return db.Select(results, fmt.Sprintf(WatcherResultQueryTmpl, ""))
}

func (result *WatcherResult) Create() error {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {
return err
}
defer db.Close()

rows, err := db.NamedQuery(WatcherResultNamedInsertTmpl, result)
if err != nil {
return err
}
defer rows.Close()

for rows.Next() {
err = rows.Scan(&result.ID)
if err != nil {
return err
}
}
return nil
}

func (result *WatcherResult) Exists() bool {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {
logger.Error().Err(err).Msg("cannot connect to database")
return false
}
defer db.Close()

return db.Get(result,
fmt.Sprintf(WatcherResultQueryTmpl, `WHERE worker_name=$1 OR id=$2`),
result.WorkerName, result.ID,
) == nil
}

func (result *WatcherResult) Update() error {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {
return err
}
defer db.Close()

_, err = db.NamedExec(WatcherResultNamedUpdateTmpl, result)
return err
}

func (results *WatcherResults) ResetRetries() error {
db, err := sqlx.Connect(dbDriver, dbConnect)
if err != nil {
return err
}
defer db.Close()

_, err = db.Exec(WatcherResultResetRetriesTmpl)
return err
}

+ 27
- 12
server.go View File

@@ -16,7 +16,7 @@ package main
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
import (
"os"
"time"
"io/ioutil"
"runtime"

@@ -25,7 +25,6 @@ import (
"tea.fen.gg/fengg/server/types"
"tea.fen.gg/fengg/server/helper"
"github.com/rs/zerolog"
customLog "github.com/gin-contrib/logger"
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/contrib/static"
"github.com/gin-gonic/gin"
@@ -33,19 +32,23 @@ import (
"gopkg.in/go-playground/validator.v9"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
)

var logger = zerolog.New(os.Stdout).
Output(zerolog.ConsoleWriter{Out: os.Stdout}).
With().
Stack().
Caller().
Timestamp().
Logger()
customLog "github.com/gin-contrib/logger"
sentry "github.com/getsentry/sentry-go"
)

func main() {
runtime.GOMAXPROCS(runtime.NumCPU())

// initialize sentry if DSN is configured
if config.App.Sentry.DSN != "" {
err := sentry.Init(sentry.ClientOptions{Dsn: config.App.Sentry.DSN})
if err != nil {
logger.Fatal().Err(err).Msg("cannot initialize sentry app")
}
defer sentry.Flush(2 * time.Second)
}

// downgrade zerolog level if gin is in release mode
if gin.Mode() == "release" {
zerolog.SetGlobalLevel(zerolog.InfoLevel)
@@ -90,12 +93,14 @@ func main() {

settings := system.Group("settings", handler.AuthenticationHandler(types.Blocking))
{
settings.GET("/accesspoint", handler.SettingsAPGETHandler)
settings.POST("/accesspoint", handler.SettingsAPPOSTHandler)
settings.GET("/whitelist", handler.SettingsWLGETHandler)
settings.POST("/whitelist", handler.SettingsWLPOSTHandler)
settings.GET("/portal", handler.SettingsPTLGETHandler)
settings.POST("/portal", handler.SettingsPTLPOSTHandler)
settings.GET("/wifi/station", handler.SettingsWifiSTAGETHandler)
settings.POST("/wifi/station", handler.SettingsWifiSTAPOSTHandler)
settings.GET("/wifi/accesspoint", handler.SettingsWifiAPGETHandler)
settings.POST("/wifi/accesspoint", handler.SettingsWifiAPPOSTHandler)
// bearer authentication
bearer := settings.Group("bearer")
{
@@ -110,6 +115,16 @@ func main() {
settings.GET("/interfaces", handler.InterfacesGETHandler)
settings.POST("/interfaces", handler.InterfacesPOSTHandler)
}

wifi := system.Group("wifi", handler.AuthenticationHandler(types.Blocking))
{
wifi.GET("/scan", handler.WifiScanHandler)
}

worker := system.Group("worker", handler.AuthenticationHandler(types.Blocking))
{
worker.GET("/info", handler.WorkerInfoHandler)
}
}
connections := apiGroup.Group("connections", handler.AuthenticationHandler(types.Blocking))
{


+ 67
- 47
src/assets/images/logo.svg View File

@@ -11,15 +11,24 @@
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 1438.57 510.24"
style="enable-background:new 0 0 1438.57 510.24;"
viewBox="0 0 1225.0301 492.19001"
xml:space="preserve"
sodipodi:docname="logo.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><metadata
id="metadata25"><rdf:RDF><cc:Work
sodipodi:docname="Fengg-10-one-f.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07, custom)"
width="1225.03"
height="492.19"><metadata
id="metadata1049"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs23" /><sodipodi:namedview
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs1047">

</defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
@@ -28,20 +37,21 @@
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1080"
id="namedview21"
inkscape:window-width="1916"
inkscape:window-height="1041"
id="namedview1045"
showgrid="false"
inkscape:zoom="0.65669011"
inkscape:cx="729.62504"
inkscape:cy="189.16207"
inkscape:zoom="0.46435003"
inkscape:cx="560.58624"
inkscape:cy="350.28792"
inkscape:window-x="1080"
inkscape:window-y="0"
inkscape:window-y="37"
inkscape:window-maximized="0"
inkscape:current-layer="Layer_1" />
inkscape:current-layer="Layer_1"
inkscape:document-rotation="0" />
<style
type="text/css"
id="style2">
id="style1021">
.st0{fill:#FFFFFF;}
.st1{fill:url(#SVGID_1_);}
.st2{fill:url(#SVGID_2_);}
@@ -49,36 +59,46 @@
.st4{fill:#101044;}
.st5{fill:url(#SVGID_4_);}
</style>

<linearGradient
id="SVGID_1_"
gradientUnits="userSpaceOnUse"
x1="12.9123"
y1="258.9881"
x2="449.26611"
y2="258.9881">
<stop
offset="0"
style="stop-color:#007BFF"
id="stop1037" />
<stop
offset="1"
style="stop-color:#30CAEA"
id="stop1039" />
</linearGradient>
<g
id="g16"
style="fill:#343a40;fill-opacity:1">
<g
id="g14"
style="fill:#343a40;fill-opacity:1">
<path
d="M 553.56,370.57 H 500.85 V 117.92 h 144.81 v 43.89 h -92.11 v 65.15 h 85.71 v 43.72 h -85.71 v 99.89 z"
id="path4"
style="fill:#343a40;fill-opacity:1" />
<path
d="m 760.68,374.02 c -31.11,0 -55.42,-8.58 -72.93,-25.75 -17.51,-17.17 -26.27,-41.47 -26.27,-72.93 0,-32.37 8.09,-57.4 24.28,-75.09 16.18,-17.68 38.56,-26.53 67.14,-26.53 27.3,0 48.56,7.78 63.77,23.33 15.21,15.55 22.81,37.04 22.81,64.46 v 25.58 h -124.6 c 0.58,14.98 5.01,26.67 13.31,35.08 8.29,8.41 19.93,12.62 34.91,12.62 11.63,0 22.64,-1.21 33.01,-3.63 10.37,-2.42 21.2,-6.28 32.49,-11.58 v 40.78 c -9.22,4.61 -19.07,8.04 -29.55,10.28 -10.49,2.26 -23.27,3.38 -38.37,3.38 z m -7.43,-162.78 c -11.18,0 -19.93,3.54 -26.27,10.63 -6.34,7.09 -9.97,17.14 -10.89,30.16 h 73.96 c -0.23,-13.02 -3.63,-23.07 -10.2,-30.16 -6.55,-7.09 -15.42,-10.63 -26.6,-10.63 z"
id="path6"
style="fill:#343a40;fill-opacity:1" />
<path
d="M 1042.98,370.57 H 990.27 V 257.72 c 0,-13.94 -2.48,-24.39 -7.43,-31.37 -4.96,-6.97 -12.85,-10.46 -23.67,-10.46 -14.75,0 -25.4,4.93 -31.97,14.78 -6.57,9.85 -9.85,26.18 -9.85,48.99 v 90.9 h -52.71 v -193.2 h 40.26 l 7.08,24.71 h 2.94 c 5.88,-9.33 13.97,-16.39 24.28,-21.17 10.31,-4.78 22.03,-7.17 35.17,-7.17 22.47,0 39.51,6.08 51.15,18.23 11.63,12.16 17.45,29.7 17.45,52.62 v 125.99 z"
id="path8"
style="fill:#343a40;fill-opacity:1" />
<path
d="m 1247.69,177.37 v 26.79 l -30.24,7.78 c 5.53,8.64 8.29,18.32 8.29,29.03 0,20.74 -7.23,36.89 -21.69,48.47 -14.46,11.58 -34.54,17.37 -60.22,17.37 l -9.5,-0.52 -7.78,-0.86 c -5.42,4.15 -8.12,8.76 -8.12,13.83 0,7.6 9.68,11.41 29.03,11.41 h 32.83 c 21.2,0 37.35,4.55 48.47,13.65 11.12,9.1 16.68,22.46 16.68,40.09 0,22.58 -9.42,40.09 -28.25,52.53 -18.84,12.44 -45.88,18.66 -81.13,18.66 -26.96,0 -47.55,-4.7 -61.78,-14.08 -14.23,-9.39 -21.34,-22.55 -21.34,-39.49 0,-11.64 3.63,-21.37 10.89,-29.21 7.26,-7.83 17.91,-13.42 31.97,-16.76 -5.42,-2.3 -10.14,-6.08 -14.17,-11.32 -4.03,-5.24 -6.05,-10.8 -6.05,-16.68 0,-7.37 2.13,-13.51 6.39,-18.4 4.26,-4.9 10.43,-9.7 18.49,-14.43 -10.14,-4.38 -18.17,-11.41 -24.11,-21.08 -5.93,-9.68 -8.9,-21.08 -8.9,-34.22 0,-21.08 6.85,-37.38 20.56,-48.9 13.71,-11.52 33.29,-17.28 58.75,-17.28 5.41,0 11.84,0.49 19.27,1.47 7.43,0.98 12.18,1.7 14.26,2.16 h 67.4 z m -149.13,220.5 c 0,7.26 3.48,12.96 10.46,17.11 6.97,4.15 16.73,6.22 29.29,6.22 18.89,0 33.7,-2.59 44.41,-7.78 10.71,-5.19 16.07,-12.27 16.07,-21.25 0,-7.26 -3.17,-12.27 -9.5,-15.04 -6.34,-2.76 -16.13,-4.15 -29.38,-4.15 h -27.3 c -9.68,0 -17.77,2.27 -24.28,6.83 -6.52,4.55 -9.77,10.57 -9.77,18.06 z m 19.18,-157.26 c 0,10.48 2.39,18.78 7.17,24.88 4.78,6.11 12.07,9.16 21.86,9.16 9.91,0 17.17,-3.05 21.77,-9.16 4.61,-6.11 6.91,-14.4 6.91,-24.88 0,-23.27 -9.56,-34.91 -28.69,-34.91 -19.34,0.01 -29.02,11.64 -29.02,34.91 z"
id="path10"
style="fill:#343a40;fill-opacity:1" />
<path
d="m 1429.94,177.37 v 26.79 l -30.24,7.78 c 5.53,8.64 8.29,18.32 8.29,29.03 0,20.74 -7.23,36.89 -21.69,48.47 -14.46,11.58 -34.54,17.37 -60.22,17.37 l -9.5,-0.52 -7.78,-0.86 c -5.42,4.15 -8.12,8.76 -8.12,13.83 0,7.6 9.68,11.41 29.03,11.41 h 32.83 c 21.2,0 37.35,4.55 48.47,13.65 11.12,9.1 16.68,22.46 16.68,40.09 0,22.58 -9.42,40.09 -28.25,52.53 -18.84,12.44 -45.88,18.66 -81.13,18.66 -26.96,0 -47.55,-4.7 -61.78,-14.08 -14.23,-9.39 -21.34,-22.55 -21.34,-39.49 0,-11.64 3.63,-21.37 10.89,-29.21 7.26,-7.83 17.91,-13.42 31.97,-16.76 -5.42,-2.3 -10.14,-6.08 -14.17,-11.32 -4.03,-5.24 -6.05,-10.8 -6.05,-16.68 0,-7.37 2.13,-13.51 6.39,-18.4 4.26,-4.9 10.43,-9.7 18.49,-14.43 -10.14,-4.38 -18.17,-11.41 -24.11,-21.08 -5.93,-9.68 -8.9,-21.08 -8.9,-34.22 0,-21.08 6.85,-37.38 20.56,-48.9 13.71,-11.52 33.29,-17.28 58.75,-17.28 5.41,0 11.84,0.49 19.27,1.47 7.43,0.98 12.18,1.7 14.26,2.16 h 67.4 z m -149.14,220.5 c 0,7.26 3.48,12.96 10.46,17.11 6.97,4.15 16.73,6.22 29.29,6.22 18.89,0 33.7,-2.59 44.41,-7.78 10.71,-5.19 16.07,-12.27 16.07,-21.25 0,-7.26 -3.17,-12.27 -9.5,-15.04 -6.34,-2.76 -16.13,-4.15 -29.38,-4.15 h -27.3 c -9.68,0 -17.77,2.27 -24.28,6.83 -6.51,4.55 -9.77,10.57 -9.77,18.06 z m 19.19,-157.26 c 0,10.48 2.39,18.78 7.17,24.88 4.78,6.11 12.07,9.16 21.86,9.16 9.91,0 17.17,-3.05 21.77,-9.16 4.61,-6.11 6.91,-14.4 6.91,-24.88 0,-23.27 -9.56,-34.91 -28.69,-34.91 -19.35,0.01 -29.02,11.64 -29.02,34.91 z"
id="path12"
style="fill:#343a40;fill-opacity:1" />
</g>
</g>
<path
d="M12.91,12.89v236.42c0,83.73,44.16,163.09,118.27,212.49c29.51,19.46,61.43,33.67,94.66,41.97l5.25,1.31l5.03-1.31 c33.23-8.31,65.15-22.52,94.66-41.97c74.11-49.41,118.49-128.76,118.49-212.49V12.89H12.91z M346.83,148.41H197.82v68.25h71.66 v77.35h-80.19v119.44l-73.94-56.88V72.77h231.48V148.41z"
id="path18"
style="fill:#17a2b8;fill-opacity:1" />
id="g1633"
transform="translate(-12.91,-12.89)"><g
id="g1625"
transform="translate(-192)"><path
class="st0"
d="m 760.68,374.02 c -31.11,0 -55.42,-8.58 -72.93,-25.75 -17.51,-17.17 -26.27,-41.47 -26.27,-72.93 0,-32.37 8.09,-57.4 24.28,-75.09 16.18,-17.68 38.56,-26.53 67.14,-26.53 27.3,0 48.56,7.78 63.77,23.33 15.21,15.55 22.81,37.04 22.81,64.46 v 25.58 h -124.6 c 0.58,14.98 5.01,26.67 13.31,35.08 8.29,8.41 19.93,12.62 34.91,12.62 11.63,0 22.64,-1.21 33.01,-3.63 10.37,-2.42 21.2,-6.28 32.49,-11.58 v 40.78 c -9.22,4.61 -19.07,8.04 -29.55,10.28 -10.49,2.26 -23.27,3.38 -38.37,3.38 z m -7.43,-162.78 c -11.18,0 -19.93,3.54 -26.27,10.63 -6.34,7.09 -9.97,17.14 -10.89,30.16 h 73.96 c -0.23,-13.02 -3.63,-23.07 -10.2,-30.16 -6.55,-7.09 -15.42,-10.63 -26.6,-10.63 z"
id="path1025"
style="fill:#343a40;fill-opacity:1" /><path
class="st0"
d="M 1042.98,370.57 H 990.27 V 257.72 c 0,-13.94 -2.48,-24.39 -7.43,-31.37 -4.96,-6.97 -12.85,-10.46 -23.67,-10.46 -14.75,0 -25.4,4.93 -31.97,14.78 -6.57,9.85 -9.85,26.18 -9.85,48.99 v 90.9 h -52.71 v -193.2 h 40.26 l 7.08,24.71 h 2.94 c 5.88,-9.33 13.97,-16.39 24.28,-21.17 10.31,-4.78 22.03,-7.17 35.17,-7.17 22.47,0 39.51,6.08 51.15,18.23 11.63,12.16 17.45,29.7 17.45,52.62 v 125.99 z"
id="path1027"
style="fill:#343a40;fill-opacity:1" /><path
class="st0"
d="m 1247.69,177.37 v 26.79 l -30.24,7.78 c 5.53,8.64 8.29,18.32 8.29,29.03 0,20.74 -7.23,36.89 -21.69,48.47 -14.46,11.58 -34.54,17.37 -60.22,17.37 l -9.5,-0.52 -7.78,-0.86 c -5.42,4.15 -8.12,8.76 -8.12,13.83 0,7.6 9.68,11.41 29.03,11.41 h 32.83 c 21.2,0 37.35,4.55 48.47,13.65 11.12,9.1 16.68,22.46 16.68,40.09 0,22.58 -9.42,40.09 -28.25,52.53 -18.84,12.44 -45.88,18.66 -81.13,18.66 -26.96,0 -47.55,-4.7 -61.78,-14.08 -14.23,-9.39 -21.34,-22.55 -21.34,-39.49 0,-11.64 3.63,-21.37 10.89,-29.21 7.26,-7.83 17.91,-13.42 31.97,-16.76 -5.42,-2.3 -10.14,-6.08 -14.17,-11.32 -4.03,-5.24 -6.05,-10.8 -6.05,-16.68 0,-7.37 2.13,-13.51 6.39,-18.4 4.26,-4.9 10.43,-9.7 18.49,-14.43 -10.14,-4.38 -18.17,-11.41 -24.11,-21.08 -5.93,-9.68 -8.9,-21.08 -8.9,-34.22 0,-21.08 6.85,-37.38 20.56,-48.9 13.71,-11.52 33.29,-17.28 58.75,-17.28 5.41,0 11.84,0.49 19.27,1.47 7.43,0.98 12.18,1.7 14.26,2.16 h 67.4 z m -149.13,220.5 c 0,7.26 3.48,12.96 10.46,17.11 6.97,4.15 16.73,6.22 29.29,6.22 18.89,0 33.7,-2.59 44.41,-7.78 10.71,-5.19 16.07,-12.27 16.07,-21.25 0,-7.26 -3.17,-12.27 -9.5,-15.04 -6.34,-2.76 -16.13,-4.15 -29.38,-4.15 h -27.3 c -9.68,0 -17.77,2.27 -24.28,6.83 -6.52,4.55 -9.77,10.57 -9.77,18.06 z m 19.18,-157.26 c 0,10.48 2.39,18.78 7.17,24.88 4.78,6.11 12.07,9.16 21.86,9.16 9.91,0 17.17,-3.05 21.77,-9.16 4.61,-6.11 6.91,-14.4 6.91,-24.88 0,-23.27 -9.56,-34.91 -28.69,-34.91 -19.34,0.01 -29.02,11.64 -29.02,34.91 z"
id="path1029"
style="fill:#343a40;fill-opacity:1" /><path
class="st0"
d="m 1429.94,177.37 v 26.79 l -30.24,7.78 c 5.53,8.64 8.29,18.32 8.29,29.03 0,20.74 -7.23,36.89 -21.69,48.47 -14.46,11.58 -34.54,17.37 -60.22,17.37 l -9.5,-0.52 -7.78,-0.86 c -5.42,4.15 -8.12,8.76 -8.12,13.83 0,7.6 9.68,11.41 29.03,11.41 h 32.83 c 21.2,0 37.35,4.55 48.47,13.65 11.12,9.1 16.68,22.46 16.68,40.09 0,22.58 -9.42,40.09 -28.25,52.53 -18.84,12.44 -45.88,18.66 -81.13,18.66 -26.96,0 -47.55,-4.7 -61.78,-14.08 -14.23,-9.39 -21.34,-22.55 -21.34,-39.49 0,-11.64 3.63,-21.37 10.89,-29.21 7.26,-7.83 17.91,-13.42 31.97,-16.76 -5.42,-2.3 -10.14,-6.08 -14.17,-11.32 -4.03,-5.24 -6.05,-10.8 -6.05,-16.68 0,-7.37 2.13,-13.51 6.39,-18.4 4.26,-4.9 10.43,-9.7 18.49,-14.43 -10.14,-4.38 -18.17,-11.41 -24.11,-21.08 -5.93,-9.68 -8.9,-21.08 -8.9,-34.22 0,-21.08 6.85,-37.38 20.56,-48.9 13.71,-11.52 33.29,-17.28 58.75,-17.28 5.41,0 11.84,0.49 19.27,1.47 7.43,0.98 12.18,1.7 14.26,2.16 h 67.4 z m -149.14,220.5 c 0,7.26 3.48,12.96 10.46,17.11 6.97,4.15 16.73,6.22 29.29,6.22 18.89,0 33.7,-2.59 44.41,-7.78 10.71,-5.19 16.07,-12.27 16.07,-21.25 0,-7.26 -3.17,-12.27 -9.5,-15.04 -6.34,-2.76 -16.13,-4.15 -29.38,-4.15 h -27.3 c -9.68,0 -17.77,2.27 -24.28,6.83 -6.51,4.55 -9.77,10.57 -9.77,18.06 z m 19.19,-157.26 c 0,10.48 2.39,18.78 7.17,24.88 4.78,6.11 12.07,9.16 21.86,9.16 9.91,0 17.17,-3.05 21.77,-9.16 4.61,-6.11 6.91,-14.4 6.91,-24.88 0,-23.27 -9.56,-34.91 -28.69,-34.91 -19.35,0.01 -29.02,11.64 -29.02,34.91 z"
id="path1031"
style="fill:#343a40;fill-opacity:1" /></g><path
class="st1"
d="m 12.91,12.89 v 236.42 c 0,83.73 44.16,163.09 118.27,212.49 29.51,19.46 61.43,33.67 94.66,41.97 l 5.25,1.31 5.03,-1.31 c 33.23,-8.31 65.15,-22.52 94.66,-41.97 74.11,-49.41 118.49,-128.76 118.49,-212.49 V 12.89 Z M 346.83,148.41 H 197.82 v 68.25 h 71.66 v 77.35 H 189.29 V 413.45 L 115.35,356.57 V 72.77 h 231.48 z"
id="path1042"
style="fill:#17a2b8;fill-opacity:1" /></g>
</svg>

+ 0
- 137
src/components/AccessPoint.vue View File

@@ -1,137 +0,0 @@
<template>
<div>
<form @submit="onSubmit">
<md-card>
<md-card-header>
<div class="md-title">{{ $t('accesspoint.title') }}</div>
</md-card-header>

<md-card-content>
<md-switch v-model="enabled">
<template v-if="!enabled">{{ $t('accesspoint.enable') }}</template>
<template v-else>{{ $t('accesspoint.disable') }}</template>
</md-switch>

<div v-if="enabled">
<md-field>
<label>{{ $t('accesspoint.form.interface.label') }}</label>
<md-select v-model="selectedCardIdx">
<md-option
v-for="(item, index) in wirelessCardsIdx"
v-bind:key="'cards' + index"
:value="item">{{ networkInterfaces[item].name }}</md-option>
</md-select>
<span class="md-helper-text">
{{ $t('accesspoint.form.interface.description') }}
</span>
</md-field>
<template v-if="selectedCardIdx !== -1">
<md-field>
<label>{{ $t('accesspoint.form.network.label') }}</label>
<md-input v-model="selectedCardNetwork().network" disabled></md-input>
</md-field>
<md-field>
<label>{{ $t('accesspoint.form.ssid.label') }}</label>
<md-input v-model="ssid" pattern="^[\w\d\-_]{2,}$" required></md-input>
</md-field>
<md-field>
<label>{{ $t('accesspoint.form.password.label') }}</label>
<md-input
v-model="passphrase"
type="password"
minlength="13"
required
></md-input>
</md-field>
</template>
</div>
</md-card-content>

<md-card-actions>
<md-button
:disabled="submitted"
type="submit"
class="md-primary"
>{{ $t('accesspoint.button.submit') }}</md-button>
</md-card-actions>
</md-card>
</form>
</div>
</template>

<script>
import { Api, onError } from '@/api.js'

export default {
name: 'AccessPoint',
props: [],
data () {
return {
submitted: false,
success: false,
networks: [],
networkInterfaces: [],
wirelessCardsIdx: [],
selectedCardIdx: -1,
enabled: false,
ssid: '',
passphrase: ''
}
},
mounted () {
Api.get('/system/settings/accesspoint').then(response => {
if (response.data === null) {
return
}
this.ssid = response.data.data.ssid
this.enabled = response.data.data.enabled
this.passphrase = response.data.data.passphrase
}).catch(error => onError(this, error))

Api.get('/system/settings/networks').then(response => {
if (response.data === null) {
return
}
this.networks = response.data.data
}).catch(error => onError(this, error))

Api.get('/system/settings/interfaces').then(response => {
if (response.data === null) {
return
}
this.networkInterfaces = response.data.data
this.wirelessCardsIdx = Object.keys(this.networkInterfaces).filter(
a => this.networkInterfaces[a].wirelessCard
)
if (this.wirelessCardsIdx.length > 0) {
this.selectedCard = this.wirelessCardsIdx[0]
}
}).catch(error => onError(this, error))
},
methods: {
selectedCardNetwork () {
var id = this.networkInterfaces[this.selectedCardIdx].networkId
var networks = this.networks.filter(n => n.id === id)
if (networks.length > 0) {
return networks[0]
}
return null
},
onSubmit (evt) {
evt.preventDefault()
this.submitted = true
Api.post('/system/settings/accesspoint', {
enabled: this.enabled,
interfaceId: this.networkInterfaces[this.selectedCardIdx].id,
passphrase: this.passphrase,
ssid: this.ssid
}).then(() => {
this.success = true
}).catch((error) => onError(this, error)).finally(() => {
this.submitted = false
setTimeout(() => { this.success = false }, 2000)
})
}
}
}
</script>

+ 3
- 2
src/components/EmptyState.vue View File

@@ -1,7 +1,7 @@
<template>
<md-empty-state>
<md-icon class="md-empty-state-icon">
<font-awesome-icon :icon="icon" />
<font-awesome-icon :class="cssClass" :icon="icon" />
</md-icon>
<strong class="md-empty-state-label">{{ label }}</strong>
<p class="md-empty-state-description">{{ description }}</p>
@@ -14,7 +14,8 @@ export default {
props: [
'title',
'text',
'iconClass'
'iconClass',
'cssClass'
],
data () {
return {


+ 11
- 2
src/components/Navigation.vue View File

@@ -84,9 +84,18 @@
<span class="md-list-item-text">{{ $t('navigation.vpn') }}</span>
</md-list-item>

<md-list-item :to="{name: 'AccessPoint'}">
<md-list-item md-expand>
<md-icon><font-awesome-icon icon="wifi" /></md-icon>
<span class="md-list-item-text">{{ $t('navigation.accessPoint') }}</span>
<span class="md-list-item-text">{{ $t('navigation.wireless.title') }}</span>

<md-list slot="md-expand">
<md-list-item class="md-inset" :to="{name: 'WirelessAccessPoint'}">
{{ $t('navigation.wireless.accesspoint') }}
</md-list-item>
<md-list-item class="md-inset" :to="{name: 'WirelessStation'}">
{{ $t('navigation.wireless.station') }}
</md-list-item>
</md-list>
</md-list-item>

<md-list-item :to="{name: 'UserPortal'}">


+ 86
- 0
src/components/wireless/AccessPoint.vue View File

@@ -0,0 +1,86 @@
<template>
<div>
<md-card>
<md-card-header>
<div class="md-title">{{ $t('wireless.accesspoint.title') }}</div>
</md-card-header>

<md-card-content>
<md-switch v-model="enabled">
<template v-if="enabled">{{ $t('wireless.accesspoint.enable') }}</template>
<template v-else>{{ $t('wireless.accesspoint.disable') }}</template>
</md-switch>

<template v-if="enabled">
<md-field>
<label>{{ $t('wireless.accesspoint.form.ssid.label') }}</label>
<md-input v-model="ssid" pattern="^[\w\d\-_]{2,}$" required></md-input>
</md-field>
<md-field>
<label>{{ $t('wireless.accesspoint.form.password.label') }}</label>
<md-input
v-model="passphrase"
type="password"
minlength="13"
required
></md-input>
</md-field>
</template>
</md-card-content>

<md-card-actions>
<md-button
:disabled="submitted"
@click="onSubmit"
class="md-primary"
>{{ $t('wireless.accesspoint.button.submit') }}</md-button>
</md-card-actions>
</md-card>
</div>
</template>

<script>
import { Api, onError } from '@/api.js'

export default {
name: 'Wireless',
props: [],
data () {
return {
enabled: false,
submitted: false,
ssid: null,
passphrase: null,
extraConfiguration: null
}
},
mounted () {
Api.get('/system/settings/wifi/accesspoint').then(response => {
if (typeof response.data === 'undefined' || response.data.type !== 'success') {
return
}

var result = response.data.data
this.enabled = result.enabled
this.passphrase = result.passphrase
this.ssid = result.ssid
this.extraConfiguration = result.extraConfiguration
}).catch((error) => onError(this, error))
},
methods: {
onSubmit () {
this.submitted = true

Api.post('/system/settings/wifi/accesspoint', {
enabled: this.enabled,
passphrase: this.passphrase,
ssid: this.ssid
}).then(() => {
// TODO notify the user
}).catch((error) => onError(this, error)).finally(() => {
this.submitted = false
})
}
}
}
</script>

+ 276
- 0
src/components/wireless/Station.vue View File

@@ -0,0 +1,276 @@
<style scoped>
.md-list {
height: 250px;
overflow-y: scroll;
}

.md-layout {
width: 100%;
}

.md-layout-item {
align-self: center;
}

.spinner {
/* md-list height plus toolbar height */
height: 314px;
}

.md-center {
text-align: center;
}
</style>

<template>
<md-steppers :md-active-step.sync="steppers.active" md-vertical md-linear>
<md-step
id="first"
:md-label="$t('wireless.station.firstStep.label')"
:md-done.sync="steppers.first.done"
>
<p>{{ $t('wireless.station.firstStep.description') }}</p>
<md-button
class="md-secondary md-raised"
@click="switchTab('first', 'second')"
>{{ $t('wireless.station.scan') }}</md-button>
</md-step>

<md-step
id="second"
:md-label="$t('wireless.station.secondStep.label')"
:md-description="$t('wireless.station.secondStep.description')"
:md-done.sync="steppers.first.done"
>
<md-content v-if="networks === null" class="spinner md-center">
<md-progress-spinner
:md-diameter="100"
:md-stroke="10"
md-mode="indeterminate"
></md-progress-spinner>
</md-content>
<EmptyState
v-else-if="networks.length === 0"
:title="$t('wireless.station.noStation.title')"
:text="$t('wireless.station.noStation.description')"
icon-class="sticky-note"
/>
<template v-else>
<md-toolbar :md-elevation="1">
<div class="md-layout">
<div
:class="toolbarClasses(index)"
v-for="(item, index) in capKeys(networks)"
v-bind:key="'wifiheaderkeys' + index"
>
{{ item }}
</div>
</div>
</md-toolbar>

<md-list>
<div
v-for="item in networks"
v-bind:key="'wifilist' + item.ssid"
>
<md-list-item>
<div class="md-layout">
<div class="md-layout-item">
<md-radio v-model="ssid" :value="item.ssid">{{ item.ssid }}</md-radio>
</div>
<div class="md-layout-item md-size-10 md-center">{{ item.dBm }}</div>
<div class="md-layout-item md-size-10 md-center">{{ item.quality }}%</div>
</div>
</md-list-item>
<md-divider></md-divider>
</div>
</md-list>
</template>

<md-button
style="width: 100%;"
:disabled="steppers.second.btnDisabled"
class="md-secondary md-raised"
@click="scanWifiNetworks()"
>{{ $t('wireless.station.scan') }}</md-button>

<md-field v-if="ssid !== null">
<label>Password field without toggle</label>
<md-input v-model="passphrase" type="password"></md-input>
</md-field>

<md-button
class="md-primary md-raised"
@click="switchTab(undefined, 'first')"
>{{ $t('wireless.station.back') }}</md-button>
<md-button
v-if="ssid !== null"
:disabled="submitted"
class="bs-success"
@click="onConnect"
>{{ $t('wireless.station.connect') }}</md-button>
</md-step>

<md-step
id="third"
:md-label="$t('wireless.station.thirdStep.label')"
:md-description="$t('wireless.station.thirdStep.description')"
:md-done.sync="steppers.third.done"
>
<EmptyState
v-if="connected"
:title="$t('wireless.station.success.title')"
:text=&#