Merge branch 'ConnectedPeers'
This commit is contained in:
		
						commit
						12c5e71e62
					
				| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
# Build stage
 | 
					# Build stage
 | 
				
			||||||
FROM golang:1.14.2-alpine3.11 as builder
 | 
					FROM golang:1.16.7-alpine3.14 as builder
 | 
				
			||||||
LABEL maintainer="Khanh Ngo <k@ndk.name"
 | 
					LABEL maintainer="Khanh Ngo <k@ndk.name"
 | 
				
			||||||
ARG BUILD_DEPENDENCIES="npm \
 | 
					ARG BUILD_DEPENDENCIES="npm \
 | 
				
			||||||
    yarn"
 | 
					    yarn"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,13 @@ You can take a look at this example of [docker-compose.yml](https://github.com/n
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
docker-compose up
 | 
					docker-compose up
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There is a Status option that needs docker to be able to access the network of the host in order to read the 
 | 
				
			||||||
 | 
					wireguard interface stats. See the `cap_add` and `network_mode` options on the docker-compose.yaml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Environment Variables
 | 
					### Environment Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,13 +5,14 @@ services:
 | 
				
			||||||
    build: .
 | 
					    build: .
 | 
				
			||||||
    #image: ngoduykhanh/wireguard-ui:latest
 | 
					    #image: ngoduykhanh/wireguard-ui:latest
 | 
				
			||||||
    container_name: wgui
 | 
					    container_name: wgui
 | 
				
			||||||
 | 
					    cap_add:
 | 
				
			||||||
 | 
					      - NET_ADMIN
 | 
				
			||||||
 | 
					    network_mode: host
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
      - SENDGRID_API_KEY
 | 
					      - SENDGRID_API_KEY
 | 
				
			||||||
      - EMAIL_FROM
 | 
					      - EMAIL_FROM
 | 
				
			||||||
      - EMAIL_FROM_NAME
 | 
					      - EMAIL_FROM_NAME
 | 
				
			||||||
      - SESSION_SECRET
 | 
					      - SESSION_SECRET
 | 
				
			||||||
    ports:
 | 
					 | 
				
			||||||
      - 5000:5000
 | 
					 | 
				
			||||||
    logging:
 | 
					    logging:
 | 
				
			||||||
      driver: json-file
 | 
					      driver: json-file
 | 
				
			||||||
      options:
 | 
					      options:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										3
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										3
									
								
								go.mod
								
								
								
								
							| 
						 | 
					@ -17,7 +17,8 @@ require (
 | 
				
			||||||
	github.com/sendgrid/rest v2.6.4+incompatible // indirect
 | 
						github.com/sendgrid/rest v2.6.4+incompatible // indirect
 | 
				
			||||||
	github.com/sendgrid/sendgrid-go v3.10.0+incompatible
 | 
						github.com/sendgrid/sendgrid-go v3.10.0+incompatible
 | 
				
			||||||
	github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086
 | 
						github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086
 | 
				
			||||||
	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200324154536-ceff61240acf
 | 
						golang.zx2c4.com/wireguard v0.0.20200121 // indirect
 | 
				
			||||||
 | 
						golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c
 | 
				
			||||||
	gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
 | 
						gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
 | 
				
			||||||
	gopkg.in/go-playground/validator.v9 v9.31.0
 | 
						gopkg.in/go-playground/validator.v9 v9.31.0
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										68
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										68
									
								
								go.sum
								
								
								
								
							| 
						 | 
					@ -35,8 +35,11 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
 | 
				
			||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 | 
					github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 | 
				
			||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 | 
					github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 | 
				
			||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 | 
					github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 | 
				
			||||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 | 
					 | 
				
			||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
					github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
 | 
					github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
 | 
					github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
 | 
					github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 | 
				
			||||||
 | 
					github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 | 
					github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 | 
				
			||||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
 | 
					github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
 | 
				
			||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
 | 
					github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
 | 
				
			||||||
| 
						 | 
					@ -48,8 +51,16 @@ github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z
 | 
				
			||||||
github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 h1:EFT6MH3igZK/dIVqgGbTqWVvkZ7wJ5iGN03SVtvvdd8=
 | 
					github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 h1:EFT6MH3igZK/dIVqgGbTqWVvkZ7wJ5iGN03SVtvvdd8=
 | 
				
			||||||
github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25/go.mod h1:sWkGw/wsaHtRsT9zGQ/WyJCotGWG/Anow/9hsAcBWRw=
 | 
					github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25/go.mod h1:sWkGw/wsaHtRsT9zGQ/WyJCotGWG/Anow/9hsAcBWRw=
 | 
				
			||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 | 
					github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 | 
				
			||||||
 | 
					github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA=
 | 
				
			||||||
 | 
					github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
 | 
				
			||||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
 | 
					github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
 | 
				
			||||||
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
 | 
					github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
 | 
				
			||||||
 | 
					github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
 | 
				
			||||||
 | 
					github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=
 | 
				
			||||||
 | 
					github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=
 | 
				
			||||||
 | 
					github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=
 | 
				
			||||||
 | 
					github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b h1:c3NTyLNozICy8B4mlMXemD3z/gXgQzVXZS/HqT+i3do=
 | 
				
			||||||
 | 
					github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=
 | 
				
			||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 | 
					github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 | 
				
			||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 | 
					github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 | 
				
			||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 | 
					github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 | 
				
			||||||
| 
						 | 
					@ -73,10 +84,21 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
 | 
				
			||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
 | 
					github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
 | 
				
			||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 | 
					github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 | 
				
			||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 | 
					github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 | 
				
			||||||
 | 
					github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY=
 | 
				
			||||||
 | 
					github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
 | 
				
			||||||
 | 
					github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
 | 
				
			||||||
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
 | 
					github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
 | 
				
			||||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
 | 
					github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
 | 
				
			||||||
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
 | 
					github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
 | 
				
			||||||
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
 | 
					github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
 | 
				
			||||||
 | 
					github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
 | 
				
			||||||
 | 
					github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
 | 
				
			||||||
 | 
					github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
 | 
				
			||||||
 | 
					github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
 | 
				
			||||||
 | 
					github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=
 | 
				
			||||||
 | 
					github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0=
 | 
				
			||||||
 | 
					github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=
 | 
				
			||||||
 | 
					github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
 | 
				
			||||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
 | 
					github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
 | 
				
			||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
					github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
				
			||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
					github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
				
			||||||
| 
						 | 
					@ -130,9 +152,11 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
					golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
					golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
					golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
					golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
 | 
				
			||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
					golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
				
			||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
					golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
				
			||||||
| 
						 | 
					@ -142,8 +166,15 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL
 | 
				
			||||||
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
					golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
				
			||||||
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
					golang.org/x/net v0.0.0-20191007182048-72f939374954/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-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
				
			||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
					golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20210504132125-bbd867fde50d h1:nTDGCTeAu2LhcsHTRzjyIUbZHCJ4QePArsm27Hka0UM=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
				
			||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
					golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
				
			||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
					golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
				
			||||||
| 
						 | 
					@ -161,21 +192,40 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
 | 
				
			||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
 | 
					golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 | 
				
			||||||
 | 
					golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
				
			||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
					golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
				
			||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 | 
					 | 
				
			||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 | 
					golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 | 
				
			||||||
 | 
					golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
				
			||||||
 | 
					golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
 | 
				
			||||||
 | 
					golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-20190608022120-eacb66d2a7c3/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 | 
					golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 | 
				
			||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 | 
					 | 
				
			||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
					golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
				
			||||||
 | 
					golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 | 
				
			||||||
 | 
					golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
				
			||||||
 | 
					golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg=
 | 
				
			||||||
golang.zx2c4.com/wireguard v0.0.20200121 h1:vcswa5Q6f+sylDfjqyrVNNrjsFUUbPsgAQTBCAg/Qf8=
 | 
					golang.zx2c4.com/wireguard v0.0.20200121 h1:vcswa5Q6f+sylDfjqyrVNNrjsFUUbPsgAQTBCAg/Qf8=
 | 
				
			||||||
golang.zx2c4.com/wireguard v0.0.20200121/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=
 | 
					golang.zx2c4.com/wireguard v0.0.20200121/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=
 | 
				
			||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200324154536-ceff61240acf h1:rWUZHukj3poXegPQMZOXgxjTGIBe3mLNHNVvL5DsHus=
 | 
					golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c h1:ADNrRDI5NR23/TUCnEmlLZLt4u9DnZ2nwRkPrAcFvto=
 | 
				
			||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200324154536-ceff61240acf/go.mod h1:UdS9frhv65KTfwxME1xE8+rHYoFpbm36gOud1GhBe9c=
 | 
					golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ=
 | 
				
			||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 | 
					gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 | 
				
			||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 | 
					gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 | 
				
			||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
					gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +15,7 @@ import (
 | 
				
			||||||
	"github.com/labstack/echo/v4"
 | 
						"github.com/labstack/echo/v4"
 | 
				
			||||||
	"github.com/labstack/gommon/log"
 | 
						"github.com/labstack/gommon/log"
 | 
				
			||||||
	"github.com/rs/xid"
 | 
						"github.com/rs/xid"
 | 
				
			||||||
 | 
						"golang.zx2c4.com/wireguard/wgctrl"
 | 
				
			||||||
	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 | 
						"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ngoduykhanh/wireguard-ui/emailer"
 | 
						"github.com/ngoduykhanh/wireguard-ui/emailer"
 | 
				
			||||||
| 
						 | 
					@ -452,6 +454,93 @@ func GlobalSettings(db store.IStore) echo.HandlerFunc {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Status handler
 | 
				
			||||||
 | 
					func Status(db store.IStore) echo.HandlerFunc {
 | 
				
			||||||
 | 
						type PeerVM struct {
 | 
				
			||||||
 | 
							Name              string
 | 
				
			||||||
 | 
							Email             string
 | 
				
			||||||
 | 
							PublicKey         string
 | 
				
			||||||
 | 
							ReceivedBytes     int64
 | 
				
			||||||
 | 
							TransmitBytes     int64
 | 
				
			||||||
 | 
							LastHandshakeTime time.Time
 | 
				
			||||||
 | 
							LastHandshakeRel  time.Duration
 | 
				
			||||||
 | 
							Connected         bool
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						type DeviceVM struct {
 | 
				
			||||||
 | 
							Name  string
 | 
				
			||||||
 | 
							Peers []PeerVM
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return func(c echo.Context) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wgclient, err := wgctrl.New()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
 | 
				
			||||||
 | 
									"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
 | 
				
			||||||
 | 
									"error":    err.Error(),
 | 
				
			||||||
 | 
									"devices":  nil,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							devices, err := wgclient.Devices()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
 | 
				
			||||||
 | 
									"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
 | 
				
			||||||
 | 
									"error":    err.Error(),
 | 
				
			||||||
 | 
									"devices":  nil,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							devicesVm := make([]DeviceVM, 0, len(devices))
 | 
				
			||||||
 | 
							if len(devices) > 0 {
 | 
				
			||||||
 | 
								m := make(map[string]*model.Client)
 | 
				
			||||||
 | 
								clients, err := db.GetClients(false)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
 | 
				
			||||||
 | 
										"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
 | 
				
			||||||
 | 
										"error":    err.Error(),
 | 
				
			||||||
 | 
										"devices":  nil,
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for i := range clients {
 | 
				
			||||||
 | 
									if clients[i].Client != nil {
 | 
				
			||||||
 | 
										m[clients[i].Client.PublicKey] = clients[i].Client
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								conv := map[bool]int{true: 1, false: 0}
 | 
				
			||||||
 | 
								for i := range devices {
 | 
				
			||||||
 | 
									devVm := DeviceVM{Name: devices[i].Name}
 | 
				
			||||||
 | 
									for j := range devices[i].Peers {
 | 
				
			||||||
 | 
										pVm := PeerVM{
 | 
				
			||||||
 | 
											PublicKey:         devices[i].Peers[j].PublicKey.String(),
 | 
				
			||||||
 | 
											ReceivedBytes:     devices[i].Peers[j].ReceiveBytes,
 | 
				
			||||||
 | 
											TransmitBytes:     devices[i].Peers[j].TransmitBytes,
 | 
				
			||||||
 | 
											LastHandshakeTime: devices[i].Peers[j].LastHandshakeTime,
 | 
				
			||||||
 | 
											LastHandshakeRel:  time.Since(devices[i].Peers[j].LastHandshakeTime),
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										pVm.Connected = pVm.LastHandshakeRel.Minutes() < 3.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if _client, ok := m[pVm.PublicKey]; ok {
 | 
				
			||||||
 | 
											pVm.Name = _client.Name
 | 
				
			||||||
 | 
											pVm.Email = _client.Email
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										devVm.Peers = append(devVm.Peers, pVm)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									sort.SliceStable(devVm.Peers, func(i, j int) bool { return devVm.Peers[i].Name < devVm.Peers[j].Name })
 | 
				
			||||||
 | 
									sort.SliceStable(devVm.Peers, func(i, j int) bool { return conv[devVm.Peers[i].Connected] > conv[devVm.Peers[j].Connected] })
 | 
				
			||||||
 | 
									devicesVm = append(devicesVm, devVm)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return c.Render(http.StatusOK, "status.html", map[string]interface{}{
 | 
				
			||||||
 | 
								"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
 | 
				
			||||||
 | 
								"devices":  devicesVm,
 | 
				
			||||||
 | 
								"error":    "",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GlobalSettingSubmit handler to update the global settings
 | 
					// GlobalSettingSubmit handler to update the global settings
 | 
				
			||||||
func GlobalSettingSubmit(db store.IStore) echo.HandlerFunc {
 | 
					func GlobalSettingSubmit(db store.IStore) echo.HandlerFunc {
 | 
				
			||||||
	return func(c echo.Context) error {
 | 
						return func(c echo.Context) error {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								main.go
								
								
								
								
							
							
						
						
									
										1
									
								
								main.go
								
								
								
								
							| 
						 | 
					@ -102,6 +102,7 @@ func main() {
 | 
				
			||||||
	app.POST("wg-server/keypair", handler.WireGuardServerKeyPair(db), handler.ValidSession)
 | 
						app.POST("wg-server/keypair", handler.WireGuardServerKeyPair(db), handler.ValidSession)
 | 
				
			||||||
	app.GET("/global-settings", handler.GlobalSettings(db), handler.ValidSession)
 | 
						app.GET("/global-settings", handler.GlobalSettings(db), handler.ValidSession)
 | 
				
			||||||
	app.POST("/global-settings", handler.GlobalSettingSubmit(db), handler.ValidSession)
 | 
						app.POST("/global-settings", handler.GlobalSettingSubmit(db), handler.ValidSession)
 | 
				
			||||||
 | 
						app.GET("/status", handler.Status(db), handler.ValidSession)
 | 
				
			||||||
	app.GET("/api/clients", handler.GetClients(db), handler.ValidSession)
 | 
						app.GET("/api/clients", handler.GetClients(db), handler.ValidSession)
 | 
				
			||||||
	app.GET("/api/client/:id", handler.GetClient(db), handler.ValidSession)
 | 
						app.GET("/api/client/:id", handler.GetClient(db), handler.ValidSession)
 | 
				
			||||||
	app.GET("/api/machine-ips", handler.MachineIPAddresses(), handler.ValidSession)
 | 
						app.GET("/api/machine-ips", handler.MachineIPAddresses(), handler.ValidSession)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,12 +74,18 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec
 | 
				
			||||||
		log.Fatal(err)
 | 
							log.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tmplStatusString, err := tmplBox.String("status.html")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// create template list
 | 
						// create template list
 | 
				
			||||||
	templates := make(map[string]*template.Template)
 | 
						templates := make(map[string]*template.Template)
 | 
				
			||||||
	templates["login.html"] = template.Must(template.New("login").Parse(tmplLoginString))
 | 
						templates["login.html"] = template.Must(template.New("login").Parse(tmplLoginString))
 | 
				
			||||||
	templates["clients.html"] = template.Must(template.New("clients").Parse(tmplBaseString + tmplClientsString))
 | 
						templates["clients.html"] = template.Must(template.New("clients").Parse(tmplBaseString + tmplClientsString))
 | 
				
			||||||
	templates["server.html"] = template.Must(template.New("server").Parse(tmplBaseString + tmplServerString))
 | 
						templates["server.html"] = template.Must(template.New("server").Parse(tmplBaseString + tmplServerString))
 | 
				
			||||||
	templates["global_settings.html"] = template.Must(template.New("global_settings").Parse(tmplBaseString + tmplGlobalSettingsString))
 | 
						templates["global_settings.html"] = template.Must(template.New("global_settings").Parse(tmplBaseString + tmplGlobalSettingsString))
 | 
				
			||||||
 | 
						templates["status.html"] = template.Must(template.New("status").Parse(tmplBaseString + tmplStatusString))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	e.Logger.SetLevel(log.DEBUG)
 | 
						e.Logger.SetLevel(log.DEBUG)
 | 
				
			||||||
	e.Pre(middleware.RemoveTrailingSlash())
 | 
						e.Pre(middleware.RemoveTrailingSlash())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,6 +120,14 @@
 | 
				
			||||||
                                </p>
 | 
					                                </p>
 | 
				
			||||||
                            </a>
 | 
					                            </a>
 | 
				
			||||||
                        </li>
 | 
					                        </li>
 | 
				
			||||||
 | 
					                        <li class="nav-item">
 | 
				
			||||||
 | 
					                            <a href="/status" class="nav-link {{if eq .baseData.Active "status" }}active{{end}}">
 | 
				
			||||||
 | 
					                                <i class="nav-icon fas fa-user"></i>
 | 
				
			||||||
 | 
					                                <p>
 | 
				
			||||||
 | 
					                                    Status
 | 
				
			||||||
 | 
					                                </p>
 | 
				
			||||||
 | 
					                            </a>
 | 
				
			||||||
 | 
					                        </li>
 | 
				
			||||||
                    </ul>
 | 
					                    </ul>
 | 
				
			||||||
                </nav>
 | 
					                </nav>
 | 
				
			||||||
                <!-- /.sidebar-menu -->
 | 
					                <!-- /.sidebar-menu -->
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,210 @@
 | 
				
			||||||
 | 
					{{define "title"}}
 | 
				
			||||||
 | 
					Connected Peers
 | 
				
			||||||
 | 
					{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{define "top_css"}}
 | 
				
			||||||
 | 
					{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{define "username"}}
 | 
				
			||||||
 | 
					{{ .username }}
 | 
				
			||||||
 | 
					{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{define "page_title"}}
 | 
				
			||||||
 | 
					Connected Peers
 | 
				
			||||||
 | 
					{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{define "page_content"}}
 | 
				
			||||||
 | 
					<section class="content">
 | 
				
			||||||
 | 
					    <div class="container-fluid">
 | 
				
			||||||
 | 
					        {{ if .error }}
 | 
				
			||||||
 | 
					        <div class="alert alert-warning" role="alert">{{.error}}</div>
 | 
				
			||||||
 | 
					        {{ end}}
 | 
				
			||||||
 | 
					        {{ range $dev := .devices }}
 | 
				
			||||||
 | 
					            <table class="table table-sm">
 | 
				
			||||||
 | 
					                <caption>List of connected peers for device with name {{ $dev.Name }} </caption>
 | 
				
			||||||
 | 
					              <thead>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <th scope="col">#</th>
 | 
				
			||||||
 | 
					                  <th scope="col">Name</th>
 | 
				
			||||||
 | 
					                  <th scope="col">Email</th>
 | 
				
			||||||
 | 
					                  <th scope="col">Public Key</th>
 | 
				
			||||||
 | 
					                  <th scope="col">ReceiveBytes</th>
 | 
				
			||||||
 | 
					                  <th scope="col">TransmitBytes</th>
 | 
				
			||||||
 | 
					                  <th scope="col">Connected (Approximation)</th>
 | 
				
			||||||
 | 
					                  <th scope="col">LastHandshakeTime</th>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					              </thead>
 | 
				
			||||||
 | 
					              <tbody>
 | 
				
			||||||
 | 
					              {{ range $idx, $peer := $dev.Peers }}
 | 
				
			||||||
 | 
					              <tr {{ if $peer.Connected }} class="table-success" {{ end }}>
 | 
				
			||||||
 | 
					                <th scope="row">{{ $idx }}</th>
 | 
				
			||||||
 | 
					                <td>{{ $peer.Name }}</td>
 | 
				
			||||||
 | 
					                <td>{{ $peer.Email }}</td>
 | 
				
			||||||
 | 
					                <td>{{ $peer.PublicKey }}</td>
 | 
				
			||||||
 | 
					                <td>{{ $peer.ReceivedBytes }}</td>
 | 
				
			||||||
 | 
					                <td>{{ $peer.TransmitBytes }}</td>
 | 
				
			||||||
 | 
					                <td>{{ $peer.Connected }}</td>
 | 
				
			||||||
 | 
					                <td>{{ $peer.LastHandshakeTime }}</td>
 | 
				
			||||||
 | 
					               </tr>
 | 
				
			||||||
 | 
					              {{ end }}
 | 
				
			||||||
 | 
					              </tbody>
 | 
				
			||||||
 | 
					            </table>
 | 
				
			||||||
 | 
					        {{ end }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</section>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="modal fade" id="modal_endpoint_address_suggestion">
 | 
				
			||||||
 | 
					    <div class="modal-dialog">
 | 
				
			||||||
 | 
					        <div class="modal-content">
 | 
				
			||||||
 | 
					            <div class="modal-header">
 | 
				
			||||||
 | 
					                <h4 class="modal-title">Endpoint Address Suggestion</h4>
 | 
				
			||||||
 | 
					                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
 | 
				
			||||||
 | 
					                    <span aria-hidden="true">×</span>
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="modal-body">
 | 
				
			||||||
 | 
					                <p>Following is the list of public and local IP addresses for your consideration.</p>
 | 
				
			||||||
 | 
					                <select id="ip_suggestion" class="select2"
 | 
				
			||||||
 | 
					                    data-placeholder="Select an IP address" style="width: 100%;">
 | 
				
			||||||
 | 
					                </select>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="modal-footer justify-content-between">
 | 
				
			||||||
 | 
					                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
 | 
				
			||||||
 | 
					                <button type="button" class="btn btn-success" id="btn_use_ip" disabled>Use selected IP address</button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <!-- /.modal-content -->
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <!-- /.modal-dialog -->
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<!-- /.modal -->
 | 
				
			||||||
 | 
					{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{define "bottom_js"}}
 | 
				
			||||||
 | 
					    <script>
 | 
				
			||||||
 | 
					        function submitGlobalSettings() {
 | 
				
			||||||
 | 
					            const endpoint_address = $("#endpoint_address").val();
 | 
				
			||||||
 | 
					            const dns_servers = $("#dns_servers").val().split(",");
 | 
				
			||||||
 | 
					            const mtu = $("#mtu").val();
 | 
				
			||||||
 | 
					            const persistent_keepalive = $("#persistent_keepalive").val();
 | 
				
			||||||
 | 
					            const config_file_path = $("#config_file_path").val();
 | 
				
			||||||
 | 
					            const data = {"endpoint_address": endpoint_address, "dns_servers": dns_servers, "mtu": mtu, "persistent_keepalive": persistent_keepalive, "config_file_path": config_file_path};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $.ajax({
 | 
				
			||||||
 | 
					                cache: false,
 | 
				
			||||||
 | 
					                method: 'POST',
 | 
				
			||||||
 | 
					                url: '/global-settings',
 | 
				
			||||||
 | 
					                dataType: 'json',
 | 
				
			||||||
 | 
					                contentType: "application/json",
 | 
				
			||||||
 | 
					                data: JSON.stringify(data),
 | 
				
			||||||
 | 
					                success: function(data) {
 | 
				
			||||||
 | 
					                    $("#modal_new_client").modal('hide');
 | 
				
			||||||
 | 
					                    toastr.success('Update global settings successfully');
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                error: function(jqXHR, exception) {
 | 
				
			||||||
 | 
					                    const responseJson = jQuery.parseJSON(jqXHR.responseText);
 | 
				
			||||||
 | 
					                    toastr.error(responseJson['message']);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function updateEndpointSuggestionIP() {
 | 
				
			||||||
 | 
					            $.getJSON("/api/machine-ips", null, function(data) {
 | 
				
			||||||
 | 
					                $("#ip_suggestion option").remove();
 | 
				
			||||||
 | 
					                $.each(data, function(index, item) {
 | 
				
			||||||
 | 
					                    $("#ip_suggestion").append(
 | 
				
			||||||
 | 
					                        $("<option></option>")
 | 
				
			||||||
 | 
					                            .text(item.ip_address + ' - ' + item.name)
 | 
				
			||||||
 | 
					                            .val(item.ip_address)
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                document.getElementById("btn_use_ip").disabled = false;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    </script>
 | 
				
			||||||
 | 
					    <script>
 | 
				
			||||||
 | 
					        // Wireguard Interface DNS server tag input
 | 
				
			||||||
 | 
					        $("#dns_servers").tagsInput({
 | 
				
			||||||
 | 
					            'width': '100%',
 | 
				
			||||||
 | 
					            'height': '75%',
 | 
				
			||||||
 | 
					            'interactive': true,
 | 
				
			||||||
 | 
					            'defaultText': 'Add More',
 | 
				
			||||||
 | 
					            'removeWithBackspace': true,
 | 
				
			||||||
 | 
					            'minChars': 0,
 | 
				
			||||||
 | 
					            'placeholderColor': '#666666'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Load DNS server to the form
 | 
				
			||||||
 | 
					        {{range .globalSettings.DNSServers}}
 | 
				
			||||||
 | 
					        $("#dns_servers").addTag('{{.}}');
 | 
				
			||||||
 | 
					        {{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Global setting form validation
 | 
				
			||||||
 | 
					        $(document).ready(function () {
 | 
				
			||||||
 | 
					            $.validator.setDefaults({
 | 
				
			||||||
 | 
					                submitHandler: function () {
 | 
				
			||||||
 | 
					                    submitGlobalSettings();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            $("#frm_global_settings").validate({
 | 
				
			||||||
 | 
					                rules: {
 | 
				
			||||||
 | 
					                    mtu: {
 | 
				
			||||||
 | 
					                        required: true,
 | 
				
			||||||
 | 
					                        digits: true,
 | 
				
			||||||
 | 
					                        range: [68, 65535]
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    persistent_keepalive: {
 | 
				
			||||||
 | 
					                        required: true,
 | 
				
			||||||
 | 
					                        digits: true
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    config_file_path: {
 | 
				
			||||||
 | 
					                        required: true
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                messages: {
 | 
				
			||||||
 | 
					                    mtu: {
 | 
				
			||||||
 | 
					                        required: "Please enter a MTU value",
 | 
				
			||||||
 | 
					                        digits: "MTU must be an integer",
 | 
				
			||||||
 | 
					                        range: "MTU must be in range 68..65535"
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    persistent_keepalive: {
 | 
				
			||||||
 | 
					                        required: "Please enter a Persistent Keepalive value",
 | 
				
			||||||
 | 
					                        digits: "Persistent keepalive must be an integer"
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    config_file_path: {
 | 
				
			||||||
 | 
					                        required: "Please enter WireGuard config file path"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                errorElement: 'span',
 | 
				
			||||||
 | 
					                errorPlacement: function (error, element) {
 | 
				
			||||||
 | 
					                    error.addClass('invalid-feedback');
 | 
				
			||||||
 | 
					                    element.closest('.form-group').append(error);
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                highlight: function (element, errorClass, validClass) {
 | 
				
			||||||
 | 
					                    $(element).addClass('is-invalid');
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                unhighlight: function (element, errorClass, validClass) {
 | 
				
			||||||
 | 
					                    $(element).removeClass('is-invalid');
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Endpoint IP suggestion modal event
 | 
				
			||||||
 | 
					        $(document).ready(function () {
 | 
				
			||||||
 | 
					            $("#modal_endpoint_address_suggestion").on('shown.bs.modal', function (e) {
 | 
				
			||||||
 | 
					                updateEndpointSuggestionIP();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Use selected IP address from suggestion form
 | 
				
			||||||
 | 
					        $(document).ready(function () {
 | 
				
			||||||
 | 
					            $("#btn_use_ip").click(function () {
 | 
				
			||||||
 | 
					                const ip = $("#ip_suggestion").select2('val');
 | 
				
			||||||
 | 
					                $("#endpoint_address").val(ip);
 | 
				
			||||||
 | 
					                $("#modal_endpoint_address_suggestion").modal('hide');
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    </script>
 | 
				
			||||||
 | 
					{{end}}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue