admins can now delete devices

pull/69/head
James Batt 4 years ago
parent a569920d28
commit ddd030864c

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [next] ## [next]
### Added
- Admin users can now delete devices from the "all devices" page (issue [#57](https://github.com/Place1/wg-access-server/issues/57))
### Bug Fixes ### Bug Fixes
- Fixes website routing to solve 404s (issue [#56](https://github.com/Place1/wg-access-server/issues/56)) - Fixes website routing to solve 404s (issue [#56](https://github.com/Place1/wg-access-server/issues/56))

@ -56,7 +56,17 @@ func (d *DeviceService) DeleteDevice(ctx context.Context, req *proto.DeleteDevic
return nil, status.Errorf(codes.PermissionDenied, "not authenticated") return nil, status.Errorf(codes.PermissionDenied, "not authenticated")
} }
if err := d.DeviceManager.DeleteDevice(user.Subject, req.GetName()); err != nil { deviceOwner := user.Subject
if req.Owner != nil {
if user.Claims.Contains("admin") {
deviceOwner = req.Owner.Value
} else {
return nil, status.Errorf(codes.PermissionDenied, "must be an admin")
}
}
if err := d.DeviceManager.DeleteDevice(deviceOwner, req.GetName()); err != nil {
ctxlogrus.Extract(ctx).Error(err) ctxlogrus.Extract(ctx).Error(err)
return nil, status.Errorf(codes.Internal, "failed to delete device") return nil, status.Errorf(codes.Internal, "failed to delete device")
} }

@ -2,6 +2,7 @@ syntax = "proto3";
package proto; package proto;
import "google/protobuf/wrappers.proto";
import "google/protobuf/timestamp.proto"; import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto"; import "google/protobuf/empty.proto";
@ -45,6 +46,11 @@ message ListDevicesRes {
message DeleteDeviceReq { message DeleteDeviceReq {
string name = 1; string name = 1;
// admin's may delete a device owned
// by someone other than the current user
// if empty, defaults to the current user
google.protobuf.StringValue owner = 2;
} }
message ListAllDevicesReq { message ListAllDevicesReq {

@ -9,6 +9,7 @@ import (
proto "github.com/golang/protobuf/proto" proto "github.com/golang/protobuf/proto"
empty "github.com/golang/protobuf/ptypes/empty" empty "github.com/golang/protobuf/ptypes/empty"
timestamp "github.com/golang/protobuf/ptypes/timestamp" timestamp "github.com/golang/protobuf/ptypes/timestamp"
wrappers "github.com/golang/protobuf/ptypes/wrappers"
grpc "google.golang.org/grpc" grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes" codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status" status "google.golang.org/grpc/status"
@ -279,10 +280,14 @@ func (m *ListDevicesRes) GetItems() []*Device {
} }
type DeleteDeviceReq struct { type DeleteDeviceReq struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` // admin's may delete a device owned
XXX_unrecognized []byte `json:"-"` // by someone other than the current user
XXX_sizecache int32 `json:"-"` // if empty, defaults to the current user
Owner *wrappers.StringValue `protobuf:"bytes,2,opt,name=owner,proto3" json:"owner,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *DeleteDeviceReq) Reset() { *m = DeleteDeviceReq{} } func (m *DeleteDeviceReq) Reset() { *m = DeleteDeviceReq{} }
@ -317,6 +322,13 @@ func (m *DeleteDeviceReq) GetName() string {
return "" return ""
} }
func (m *DeleteDeviceReq) GetOwner() *wrappers.StringValue {
if m != nil {
return m.Owner
}
return nil
}
type ListAllDevicesReq struct { type ListAllDevicesReq struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
@ -400,40 +412,42 @@ func init() {
func init() { proto.RegisterFile("devices.proto", fileDescriptor_6d27ec3f2c0e2043) } func init() { proto.RegisterFile("devices.proto", fileDescriptor_6d27ec3f2c0e2043) }
var fileDescriptor_6d27ec3f2c0e2043 = []byte{ var fileDescriptor_6d27ec3f2c0e2043 = []byte{
// 513 bytes of a gzipped FileDescriptorProto // 548 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xdb, 0x6e, 0xd3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xdb, 0x6e, 0xd3, 0x4e,
0x10, 0x8d, 0x93, 0xe6, 0xe2, 0x49, 0x5c, 0xe8, 0x04, 0xaa, 0x95, 0x01, 0x35, 0x72, 0x55, 0x29, 0x10, 0xc6, 0xe3, 0xa6, 0x39, 0x78, 0x1c, 0xf7, 0xff, 0xef, 0x06, 0xaa, 0x95, 0x29, 0x34, 0x72,
0x4f, 0xa9, 0x08, 0x42, 0x82, 0x07, 0x24, 0x82, 0x5a, 0x84, 0x00, 0x21, 0x64, 0xf1, 0x6e, 0x39, 0x85, 0x94, 0xab, 0x54, 0x04, 0x21, 0xc1, 0x05, 0x12, 0x41, 0x2d, 0x42, 0x80, 0x10, 0x32, 0x08,
0xde, 0xa1, 0x5d, 0xd5, 0xb7, 0x7a, 0xb7, 0x41, 0xf9, 0x00, 0xbe, 0x93, 0x5f, 0x41, 0xbb, 0xeb, 0x89, 0x2b, 0x6b, 0x63, 0x0f, 0xa9, 0x55, 0x9f, 0xba, 0xbb, 0x49, 0x95, 0x07, 0xe0, 0x39, 0x79,
0xa4, 0x49, 0x5a, 0x2e, 0x4f, 0xf6, 0x9c, 0x73, 0xe6, 0x76, 0xc6, 0x06, 0x8f, 0xd3, 0x42, 0x24, 0x15, 0xe4, 0xdd, 0x4d, 0xea, 0x24, 0xe5, 0x70, 0x95, 0xec, 0xf7, 0x7d, 0xb3, 0x33, 0xfe, 0x8d,
0x24, 0x27, 0x65, 0x55, 0xa8, 0x02, 0xdb, 0xe6, 0xe1, 0x1f, 0x5d, 0x14, 0xc5, 0x45, 0x4a, 0xa7, 0x0d, 0x6e, 0x8c, 0x8b, 0x24, 0x42, 0x31, 0x2a, 0x79, 0x21, 0x0b, 0xd2, 0x52, 0x3f, 0xde, 0xa3,
0x26, 0x9a, 0xdf, 0x7c, 0x3f, 0x55, 0x22, 0x23, 0xa9, 0xe2, 0xac, 0xb4, 0x3a, 0xff, 0xc9, 0xae, 0x59, 0x51, 0xcc, 0x52, 0x3c, 0x53, 0xa7, 0xe9, 0xfc, 0xfb, 0xd9, 0x0d, 0x67, 0x65, 0x89, 0xdc,
0x80, 0xb2, 0x52, 0x2d, 0x2d, 0x19, 0xfc, 0x6a, 0x41, 0xe7, 0xcc, 0x94, 0x45, 0x84, 0xbd, 0x3c, 0xc4, 0xbc, 0x93, 0x6d, 0x5f, 0x26, 0x19, 0x0a, 0xc9, 0xb2, 0xd2, 0x04, 0x1e, 0x6c, 0x07, 0x30,
0xce, 0x88, 0x39, 0x23, 0x67, 0xec, 0x86, 0xe6, 0x1d, 0x1f, 0x41, 0xbb, 0xf8, 0x91, 0x53, 0xc5, 0x2b, 0xe5, 0x52, 0x9b, 0xfe, 0xcf, 0x26, 0xb4, 0xcf, 0x55, 0x5b, 0x42, 0x60, 0x3f, 0x67, 0x19,
0x9a, 0x06, 0xb4, 0x01, 0x3e, 0x03, 0x28, 0x6f, 0xe6, 0xa9, 0x48, 0xa2, 0x2b, 0x5a, 0xb2, 0x96, 0x52, 0x6b, 0x60, 0x0d, 0xed, 0x40, 0xfd, 0x27, 0xf7, 0xa0, 0x55, 0xdc, 0xe4, 0xc8, 0xe9, 0x9e,
0xa1, 0x5c, 0x8b, 0x7c, 0xa2, 0x25, 0x32, 0xe8, 0xc6, 0x9c, 0x57, 0x24, 0x25, 0xdb, 0x33, 0xdc, 0x12, 0xf5, 0x81, 0x3c, 0x04, 0x28, 0xe7, 0xd3, 0x34, 0x89, 0xc2, 0x2b, 0x5c, 0xd2, 0xa6, 0xb2,
0x2a, 0xc4, 0xd7, 0x00, 0x49, 0x45, 0xb1, 0x22, 0x1e, 0xc5, 0x8a, 0xb5, 0x47, 0xce, 0xb8, 0x3f, 0x6c, 0xad, 0xbc, 0xc7, 0x25, 0xa1, 0xd0, 0x61, 0x71, 0xcc, 0x51, 0x08, 0xba, 0xaf, 0xbc, 0xd5,
0xf5, 0x27, 0x76, 0xbe, 0xc9, 0x6a, 0xbe, 0xc9, 0xb7, 0xd5, 0x02, 0xa1, 0x5b, 0xab, 0x67, 0x0a, 0x91, 0xbc, 0x00, 0x88, 0x38, 0x32, 0x89, 0x71, 0xc8, 0x24, 0x6d, 0x0d, 0xac, 0xa1, 0x33, 0xf6,
0x9f, 0x82, 0x9b, 0x14, 0x79, 0x4e, 0x89, 0x22, 0xce, 0x3a, 0x23, 0x67, 0xdc, 0x0b, 0x6f, 0x01, 0x46, 0x7a, 0xbe, 0xd1, 0x6a, 0xbe, 0xd1, 0x97, 0xd5, 0x03, 0x04, 0xb6, 0x49, 0x4f, 0x24, 0x39,
0xfc, 0x08, 0xc3, 0x34, 0x96, 0x2a, 0xba, 0x8c, 0x73, 0x2e, 0x2f, 0xe3, 0x2b, 0x8a, 0xb4, 0x0b, 0x06, 0x3b, 0x2a, 0xf2, 0x1c, 0x23, 0x89, 0x31, 0x6d, 0x0f, 0xac, 0x61, 0x37, 0xb8, 0x15, 0xc8,
0xac, 0xfb, 0xcf, 0x0e, 0x07, 0x3a, 0xed, 0xc3, 0x2a, 0x4b, 0xe3, 0x78, 0x0c, 0x5e, 0x45, 0x09, 0x3b, 0xe8, 0xa7, 0x4c, 0xc8, 0xf0, 0x92, 0xe5, 0xb1, 0xb8, 0x64, 0x57, 0x18, 0x56, 0x14, 0x68,
0x89, 0x05, 0x45, 0xf3, 0xa5, 0x22, 0xc9, 0x7a, 0x23, 0x67, 0xdc, 0x0a, 0x07, 0x35, 0xf8, 0x4e, 0xe7, 0xaf, 0x1d, 0x0e, 0xab, 0xb2, 0xb7, 0xab, 0xaa, 0x4a, 0x27, 0xa7, 0xe0, 0x72, 0x8c, 0x30,
0x63, 0x78, 0x02, 0xfb, 0xaa, 0x8a, 0x73, 0x99, 0x09, 0x55, 0xab, 0x5c, 0xa3, 0xf2, 0x56, 0xa8, 0x59, 0x60, 0x38, 0x5d, 0x4a, 0x14, 0xb4, 0x3b, 0xb0, 0x86, 0xcd, 0xa0, 0x67, 0xc4, 0xd7, 0x95,
0x95, 0xf9, 0xd0, 0xa3, 0x9c, 0x97, 0x85, 0xc8, 0x15, 0x03, 0xe3, 0xc5, 0x3a, 0xd6, 0x2e, 0x1a, 0x46, 0x1e, 0xc3, 0x81, 0xe4, 0x2c, 0x17, 0x59, 0x22, 0x4d, 0xca, 0x56, 0x29, 0x77, 0xa5, 0xea,
0x3b, 0x23, 0xe3, 0x7a, 0xdf, 0xba, 0x68, 0x90, 0x2f, 0xda, 0xfa, 0x23, 0xe8, 0x5b, 0x9a, 0xb2, 0x98, 0x07, 0x5d, 0xcc, 0xe3, 0xb2, 0x48, 0x72, 0x49, 0x41, 0xb1, 0x58, 0x9f, 0x2b, 0x8a, 0x0a,
0x58, 0xa4, 0x6c, 0x60, 0x78, 0x9b, 0x71, 0xae, 0x11, 0x3d, 0x82, 0x15, 0x94, 0x55, 0xb1, 0x10, 0x67, 0xa8, 0xa8, 0x3b, 0x9a, 0xa2, 0x52, 0x3e, 0x56, 0xe8, 0x4f, 0xc0, 0xd1, 0x36, 0x66, 0x2c,
0x9c, 0x2a, 0xe6, 0x19, 0x8d, 0x67, 0xd0, 0xaf, 0x35, 0x18, 0xcc, 0x60, 0x30, 0xe3, 0xdc, 0xde, 0x49, 0x69, 0x4f, 0xf9, 0xba, 0xe2, 0xa2, 0x52, 0xaa, 0x11, 0x74, 0xa0, 0xe4, 0xc5, 0x22, 0x89,
0x38, 0xa4, 0xeb, 0x7b, 0xcf, 0xbc, 0x7d, 0xd0, 0xe6, 0xce, 0x41, 0x83, 0x87, 0xb0, 0xff, 0x59, 0x91, 0x53, 0x57, 0x65, 0x5c, 0xa5, 0x7e, 0x32, 0xa2, 0x3f, 0x81, 0xde, 0x24, 0x8e, 0xf5, 0x8e,
0x48, 0x65, 0x6b, 0xc8, 0x90, 0xae, 0x83, 0x97, 0x3b, 0x88, 0xc4, 0x63, 0x68, 0x0b, 0x45, 0x99, 0x03, 0xbc, 0xbe, 0x73, 0xcd, 0x9b, 0x0b, 0xdd, 0xdb, 0x5a, 0xa8, 0xff, 0x3f, 0x1c, 0x7c, 0x48,
0x64, 0xce, 0xa8, 0x35, 0xee, 0x4f, 0x3d, 0x6b, 0xf6, 0xa4, 0xee, 0x6b, 0xb9, 0xe0, 0x04, 0x1e, 0x84, 0xd4, 0x77, 0x88, 0x00, 0xaf, 0xfd, 0x67, 0x5b, 0x8a, 0x20, 0xa7, 0xd0, 0x4a, 0x24, 0x66,
0x9c, 0x51, 0x4a, 0x8a, 0xfe, 0x3a, 0x4e, 0x30, 0x84, 0x03, 0x5d, 0x7d, 0x96, 0xa6, 0x1b, 0x2d, 0x82, 0x5a, 0x83, 0xe6, 0xd0, 0x19, 0xbb, 0x1a, 0xf6, 0xc8, 0xf4, 0xd5, 0x9e, 0xff, 0x0d, 0xfe,
0x5f, 0xdd, 0x05, 0xff, 0xaf, 0xeb, 0xf4, 0x67, 0x13, 0xba, 0x75, 0x0e, 0x3e, 0x07, 0x77, 0xed, 0x3b, 0xc7, 0x14, 0x25, 0xfe, 0x79, 0x9c, 0x71, 0xfd, 0xad, 0x73, 0xc6, 0xc7, 0x3b, 0xfb, 0xfb,
0x06, 0x0e, 0x6b, 0xf9, 0xa6, 0x3f, 0xfe, 0x76, 0x8d, 0xa0, 0x81, 0x6f, 0xa0, 0xbf, 0xb1, 0x2b, 0x2c, 0x79, 0x92, 0xcf, 0xbe, 0xb2, 0x74, 0x8e, 0xe6, 0x9d, 0xf4, 0xfb, 0x70, 0x58, 0x4d, 0x34,
0x3e, 0xae, 0xf9, 0x6d, 0x47, 0xfc, 0x7b, 0x61, 0x19, 0x34, 0xf0, 0x2d, 0x0c, 0x36, 0x77, 0xc6, 0x49, 0xd3, 0xda, 0x98, 0xcf, 0x77, 0xc5, 0x7f, 0x9b, 0x74, 0xfc, 0x63, 0x0f, 0x3a, 0xa6, 0x86,
0xc3, 0x75, 0xfd, 0x2d, 0x23, 0xfc, 0xc3, 0x3b, 0x5f, 0xe9, 0xb9, 0xfe, 0x4f, 0x83, 0x06, 0xbe, 0x3c, 0x01, 0x7b, 0x4d, 0x90, 0xf4, 0x4d, 0xbc, 0xce, 0xd4, 0xdb, 0xbc, 0xc3, 0x6f, 0x90, 0x97,
0xb7, 0x66, 0xdf, 0x6e, 0x8e, 0x6c, 0xa3, 0xd9, 0x96, 0x4b, 0xfe, 0x9f, 0x18, 0x19, 0x34, 0xe6, 0xe0, 0xd4, 0xf8, 0x90, 0xfb, 0xc6, 0xdf, 0xa4, 0xe8, 0xdd, 0x29, 0x0b, 0xbf, 0x41, 0x5e, 0x41,
0x1d, 0x43, 0xbd, 0xf8, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x89, 0x1c, 0x7b, 0x9d, 0x48, 0x04, 0x00, 0xaf, 0xce, 0x89, 0x1c, 0xad, 0xef, 0xdf, 0x80, 0xe7, 0x1d, 0xed, 0x90, 0xb9, 0xa8, 0xbe, 0x6d,
0x00, 0xbf, 0x41, 0xde, 0xe8, 0x05, 0xdd, 0x3e, 0x39, 0xa1, 0xb5, 0x66, 0x1b, 0x94, 0xbc, 0xdf, 0x39,
0xc2, 0x6f, 0x4c, 0xdb, 0xca, 0x7a, 0xfa, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x66, 0x8c, 0x07, 0x7b,
0x9c, 0x04, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.

@ -7,7 +7,7 @@ const backend = window.location.origin + '/api';
export const grpc = { export const grpc = {
server: new Server(backend), server: new Server(backend),
devices: new Devices(backend), devices: new Devices(backend),
} };
// https://github.com/SafetyCulture/grpc-web-devtools // https://github.com/SafetyCulture/grpc-web-devtools
const devtools = (window as any).__GRPCWEB_DEVTOOLS__; const devtools = (window as any).__GRPCWEB_DEVTOOLS__;

@ -2,11 +2,7 @@ import React from 'react';
import CssBaseline from '@material-ui/core/CssBaseline'; import CssBaseline from '@material-ui/core/CssBaseline';
import Box from '@material-ui/core/Box'; import Box from '@material-ui/core/Box';
import Navigation from './components/Navigation'; import Navigation from './components/Navigation';
import { import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
BrowserRouter as Router,
Switch,
Route,
} from 'react-router-dom';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { grpc } from './Api'; import { grpc } from './Api';
import { AppState } from './AppState'; import { AppState } from './AppState';
@ -15,14 +11,13 @@ import { AllDevices } from './pages/admin/AllDevices';
@observer @observer
export class App extends React.Component { export class App extends React.Component {
async componentDidMount() { async componentDidMount() {
AppState.info = await grpc.server.info({}); AppState.info = await grpc.server.info({});
} }
render() { render() {
if (!AppState.info) { if (!AppState.info) {
return <p>loading...</p> return <p>loading...</p>;
} }
return ( return (
<Router> <Router>
@ -31,11 +26,11 @@ export class App extends React.Component {
<Box component="div" m={2}> <Box component="div" m={2}>
<Switch> <Switch>
<Route exact path="/" component={YourDevices} /> <Route exact path="/" component={YourDevices} />
{AppState.info.isAdmin && {AppState.info.isAdmin && (
<> <>
<Route exact path="/admin/all-devices" component={AllDevices} /> <Route exact path="/admin/all-devices" component={AllDevices} />
</> </>
} )}
</Switch> </Switch>
</Box> </Box>
</Router> </Router>

@ -2,10 +2,8 @@ import { observable } from 'mobx';
import { InfoRes } from './sdk/server_pb'; import { InfoRes } from './sdk/server_pb';
class GlobalAppState { class GlobalAppState {
@observable @observable
info?: InfoRes.AsObject; info?: InfoRes.AsObject;
} }
export const AppState = new GlobalAppState(); export const AppState = new GlobalAppState();
@ -15,5 +13,5 @@ console.info('see global app state by typing "window.AppState"');
Object.assign(window as any, { Object.assign(window as any, {
get AppState() { get AppState() {
return JSON.parse(JSON.stringify(AppState)); return JSON.parse(JSON.stringify(AppState));
} },
}); });

@ -1,8 +1,8 @@
import formatDistance from "date-fns/formatDistance"; import formatDistance from 'date-fns/formatDistance';
import timestamp_pb from 'google-protobuf/google/protobuf/timestamp_pb'; import timestamp_pb from 'google-protobuf/google/protobuf/timestamp_pb';
import { toDate } from "./Api"; import { toDate } from './Api';
import { fromResource, lazyObservable } from "mobx-utils"; import { fromResource, lazyObservable } from 'mobx-utils';
import { toast } from "./components/Toast"; import { toast } from './components/Toast';
export function sleep(seconds: number) { export function sleep(seconds: number) {
return new Promise((resolve) => { return new Promise((resolve) => {
@ -22,7 +22,7 @@ export function lastSeen(timestamp: timestamp_pb.Timestamp.AsObject | undefined)
} }
export function lazy<T>(cb: () => Promise<T>) { export function lazy<T>(cb: () => Promise<T>) {
const resource = lazyObservable<T>(async sink => { const resource = lazyObservable<T>(async (sink) => {
sink(await cb()); sink(await cb());
}); });
@ -41,7 +41,7 @@ export function autorefresh<T>(seconds: number, cb: () => Promise<T>) {
let sink: ((next: T) => void) | undefined; let sink: ((next: T) => void) | undefined;
const resource = fromResource<T>( const resource = fromResource<T>(
async s => { async (s) => {
sink = s; sink = s;
running = true; running = true;
while (running) { while (running) {
@ -51,7 +51,7 @@ export function autorefresh<T>(seconds: number, cb: () => Promise<T>) {
}, },
() => { () => {
running = false; running = false;
} },
); );
return { return {

@ -28,7 +28,6 @@ interface Props {
@observer @observer
export class AddDevice extends React.Component<Props> { export class AddDevice extends React.Component<Props> {
@observable @observable
dialogOpen = false; dialogOpen = false;
@ -81,25 +80,22 @@ export class AddDevice extends React.Component<Props> {
this.configFileUri = URL.createObjectURL(new Blob([configFile])); this.configFileUri = URL.createObjectURL(new Blob([configFile]));
this.dialogOpen = true; this.dialogOpen = true;
this.reset(); this.reset();
} catch (error) { } catch (error) {
console.log(error); console.log(error);
// TODO: unwrap grpc error message // TODO: unwrap grpc error message
this.error = 'failed'; this.error = 'failed';
} }
} };
reset = () => { reset = () => {
this.formState.name = ''; this.formState.name = '';
} };
render() { render() {
return ( return (
<> <>
<Card> <Card>
<CardHeader <CardHeader title="Add A Device" />
title="Add A Device"
/>
<CardContent> <CardContent>
<form onSubmit={this.submit}> <form onSubmit={this.submit}>
<FormControl error={!!this.error} fullWidth> <FormControl error={!!this.error} fullWidth>
@ -107,47 +103,29 @@ export class AddDevice extends React.Component<Props> {
<Input <Input
id="device-name" id="device-name"
value={this.formState.name} value={this.formState.name}
onChange={(event) => this.formState.name = event.currentTarget.value} onChange={(event) => (this.formState.name = event.currentTarget.value)}
aria-describedby="device-name-text" aria-describedby="device-name-text"
/> />
<FormHelperText id="device-name-text">{this.error}</FormHelperText> <FormHelperText id="device-name-text">{this.error}</FormHelperText>
</FormControl> </FormControl>
<Typography component="div" align="right"> <Typography component="div" align="right">
<Button <Button color="secondary" type="button" onClick={this.reset}>
color="secondary"
type="button"
onClick={this.reset}
>
Cancel Cancel
</Button> </Button>
<Button <Button color="primary" variant="contained" endIcon={<AddIcon />} type="submit">
color="primary"
variant="contained"
endIcon={<AddIcon />}
type="submit"
>
Add Add
</Button> </Button>
</Typography> </Typography>
</form> </form>
</CardContent> </CardContent>
</Card> </Card>
<Dialog <Dialog disableBackdropClick disableEscapeKeyDown maxWidth="xl" open={this.dialogOpen}>
disableBackdropClick
disableEscapeKeyDown
maxWidth="xl"
open={this.dialogOpen}
>
<DialogTitle>Get Connected</DialogTitle> <DialogTitle>Get Connected</DialogTitle>
<DialogContent> <DialogContent>
<GetConnected <GetConnected qrCodeUri={this.qrCode!} configFile={this.configFile!} configFileUri={this.configFileUri!} />
qrCodeUri={this.qrCode!}
configFile={this.configFile!}
configFileUri={this.configFileUri!}
/>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button color="secondary" variant="outlined" onClick={() => this.dialogOpen = false}> <Button color="secondary" variant="outlined" onClick={() => (this.dialogOpen = false)}>
Done Done
</Button> </Button>
</DialogActions> </DialogActions>

@ -11,7 +11,7 @@ import { lastSeen } from '../Util';
import { AppState } from '../AppState'; import { AppState } from '../AppState';
import { IconMenu } from './IconMenu'; import { IconMenu } from './IconMenu';
import { PopoverDisplay } from './PopoverDisplay'; import { PopoverDisplay } from './PopoverDisplay';
import { Device } from '../sdk/devices_pb' import { Device } from '../sdk/devices_pb';
import { grpc } from '../Api'; import { grpc } from '../Api';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
@ -42,10 +42,7 @@ export class DeviceListItem extends React.Component<Props> {
avatar={ avatar={
<Avatar style={{ backgroundColor: device.connected ? '#76de8a' : '#bdbdbd' }}> <Avatar style={{ backgroundColor: device.connected ? '#76de8a' : '#bdbdbd' }}>
{/* <DonutSmallIcon /> */} {/* <DonutSmallIcon /> */}
{device.connected {device.connected ? <WifiIcon /> : <WifiOffIcon />}
? <WifiIcon />
: <WifiOffIcon />
}
</Avatar> </Avatar>
} }
action={ action={
@ -59,7 +56,7 @@ export class DeviceListItem extends React.Component<Props> {
<CardContent> <CardContent>
<table cellPadding="5"> <table cellPadding="5">
<tbody> <tbody>
{AppState.info?.metadataEnabled && device.connected && {AppState.info?.metadataEnabled && device.connected && (
<> <>
<tr> <tr>
<td>Endpoint</td> <td>Endpoint</td>
@ -74,8 +71,8 @@ export class DeviceListItem extends React.Component<Props> {
<td>{numeral(device.receiveBytes).format('0b')}</td> <td>{numeral(device.receiveBytes).format('0b')}</td>
</tr> </tr>
</> </>
} )}
{AppState.info?.metadataEnabled && !device.connected && {AppState.info?.metadataEnabled && !device.connected && (
<> <>
<tr> <tr>
<td>Disconnected</td> <td>Disconnected</td>
@ -85,10 +82,12 @@ export class DeviceListItem extends React.Component<Props> {
<td>{lastSeen(device.lastHandshakeTime)}</td> <td>{lastSeen(device.lastHandshakeTime)}</td>
</tr> </tr>
</> </>
} )}
<tr> <tr>
<td>Public key</td> <td>Public key</td>
<td><PopoverDisplay label="show">{device.publicKey}</PopoverDisplay></td> <td>
<PopoverDisplay label="show">{device.publicKey}</PopoverDisplay>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

@ -9,7 +9,6 @@ import { AddDevice } from './AddDevice';
@observer @observer
export class Devices extends React.Component { export class Devices extends React.Component {
@observable @observable
devices = autorefresh(5, async () => { devices = autorefresh(5, async () => {
return (await grpc.devices.listDevices({})).items; return (await grpc.devices.listDevices({})).items;
@ -21,7 +20,7 @@ export class Devices extends React.Component {
render() { render() {
if (!this.devices.current) { if (!this.devices.current) {
return <p>loading...</p> return <p>loading...</p>;
} }
return ( return (
<Grid container spacing={3} justify="center"> <Grid container spacing={3} justify="center">

@ -7,7 +7,7 @@ import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem'; import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText'; import ListItemText from '@material-ui/core/ListItemText';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import DescriptionOutlined from '@material-ui/icons/DescriptionOutlined' import DescriptionOutlined from '@material-ui/icons/DescriptionOutlined';
import { MacOSIcon, IosIcon, WindowsIcon, LinuxIcon, AndroidIcon } from './Icons'; import { MacOSIcon, IosIcon, WindowsIcon, LinuxIcon, AndroidIcon } from './Icons';
import { TabPanel } from './TabPanel'; import { TabPanel } from './TabPanel';
import { Platform, getPlatform } from '../Platform'; import { Platform, getPlatform } from '../Platform';
@ -179,15 +179,12 @@ export class GetConnected extends React.Component<Props> {
</TabPanel> </TabPanel>
<TabPanel for={Platform.Unknown} value={this.state.platform}> <TabPanel for={Platform.Unknown} value={this.state.platform}>
<Grid container direction="row" justify="space-around" alignItems="center"> <Grid container direction="row" justify="space-around" alignItems="center">
<Typography variant="body1" component="pre" style={{maxWidth: '100%', overflow: 'auto'}}> <Typography variant="body1" component="pre" style={{ maxWidth: '100%', overflow: 'auto' }}>
{this.props.configFile} {this.props.configFile}
</Typography> </Typography>
<Button <Button color="primary" onClick={() => setClipboard(this.props.configFile)}>
color="primary" Copy To Clipboard
onClick={() => setClipboard(this.props.configFile)} </Button>
>
Copy To Clipboard
</Button>
</Grid> </Grid>
</TabPanel> </TabPanel>
<Grid container justify="center"> <Grid container justify="center">

@ -10,7 +10,7 @@ import Link from '@material-ui/core/Link';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import Chip from '@material-ui/core/Chip'; import Chip from '@material-ui/core/Chip';
const useStyles = makeStyles(theme => ({ const useStyles = makeStyles((theme) => ({
title: { title: {
flexGrow: 1, flexGrow: 1,
}, },
@ -23,27 +23,31 @@ export default function Navigation() {
<AppBar position="static"> <AppBar position="static">
<Toolbar> <Toolbar>
<Typography variant="h6" className={classes.title}> <Typography variant="h6" className={classes.title}>
<span>Welcome</span> <Link to="/" color="inherit" component={NavLink}>
{AppState.info?.isAdmin && Welcome
<Chip label="admin" color="secondary" variant="outlined" size="small" style={{ marginLeft: 20, background: 'white' }} /> </Link>
} {AppState.info?.isAdmin && (
<Chip
label="admin"
color="secondary"
variant="outlined"
size="small"
style={{ marginLeft: 20, background: 'white' }}
/>
)}
</Typography> </Typography>
{AppState.info?.isAdmin && {AppState.info?.isAdmin && (
<Link to="/admin/all-devices" color="inherit" component={NavLink}> <Link to="/admin/all-devices" color="inherit" component={NavLink}>
<Button color="inherit"> <Button color="inherit">All Devices</Button>
All Devices
</Button>
</Link> </Link>
} )}
{hasAuthCookie && {hasAuthCookie && (
<Link href="/signout" color="inherit"> <Link href="/signout" color="inherit">
<Button color="inherit"> <Button color="inherit">Logout</Button>
Logout
</Button>
</Link> </Link>
} )}
</Toolbar> </Toolbar>
</AppBar> </AppBar>
); );

@ -15,7 +15,13 @@ export class PopoverDisplay extends React.Component<Props> {
render() { render() {
return ( return (
<React.Fragment> <React.Fragment>
<Button size="small" variant="outlined" color="secondary" style={{padding: 0}} onClick={event => this.setState({ anchorEl: event.currentTarget })}> <Button
size="small"
variant="outlined"
color="secondary"
style={{ padding: 0 }}
onClick={(event) => this.setState({ anchorEl: event.currentTarget })}
>
{this.props.label} {this.props.label}
</Button> </Button>
<Popover <Popover

@ -0,0 +1,40 @@
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import Dialog from '@material-ui/core/Dialog';
import Typography from '@material-ui/core/Typography';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';
import Button from '@material-ui/core/Button';
import DialogContentText from '@material-ui/core/DialogContentText';
export function present<T>(content: (close: (result: T) => void) => React.ReactNode) {
const root = document.createElement('div');
document.body.appendChild(root);
return new Promise<T>((resolve) => {
const close = (result: T) => {
unmountComponentAtNode(root);
resolve(result);
};
render(<>{content(close)}</>, root);
});
}
export function confirm(msg: string): Promise<boolean> {
return present<boolean>((close) => (
<Dialog open={true} onClose={() => close(false)}>
<DialogTitle>Confirm</DialogTitle>
<DialogContent>
<DialogContentText>{msg}</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => close(false)} variant="contained" color="primary" autoFocus>
Cancel
</Button>
<Button onClick={() => close(true)} variant="outlined" color="secondary">
Ok
</Button>
</DialogActions>
</Dialog>
));
}

@ -3,8 +3,6 @@ import { Devices } from '../components/Devices';
export class YourDevices extends React.Component { export class YourDevices extends React.Component {
render() { render() {
return ( return <Devices />;
<Devices />
);
} }
} }

@ -5,21 +5,33 @@ import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer'; import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead'; import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow'; import TableRow from '@material-ui/core/TableRow';
import Button from '@material-ui/core/Button';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { grpc } from '../../Api'; import { grpc } from '../../Api';
import { lastSeen, lazy } from '../../Util'; import { lastSeen, lazy } from '../../Util';
import { Device } from '../../sdk/devices_pb';
import { confirm } from '../../components/Present';
@observer @observer
export class AllDevices extends React.Component { export class AllDevices extends React.Component {
devices = lazy(async () => { devices = lazy(async () => {
const res = await grpc.devices.listAllDevices({}); const res = await grpc.devices.listAllDevices({});
return res.items; return res.items;
}); });
deleteDevice = async (device: Device.AsObject) => {
if (await confirm('Are you sure?')) {
await grpc.devices.deleteDevice({
name: device.name,
owner: { value: device.owner },
});
await this.devices.refresh();
}
};
render() { render() {
if (!this.devices.current) { if (!this.devices.current) {
return <p>loading...</p> return <p>loading...</p>;
} }
const rows = this.devices.current; const rows = this.devices.current;
@ -27,7 +39,7 @@ export class AllDevices extends React.Component {
// show the provider column // show the provider column
// when there is more than 1 provider in use // when there is more than 1 provider in use
// i.e. not all devices are from the same auth provider. // i.e. not all devices are from the same auth provider.
const showProviderCol = rows.length >= 2 && rows.some(r => r.ownerProvider !== rows[0].ownerProvider); const showProviderCol = rows.length >= 2 && rows.some((r) => r.ownerProvider !== rows[0].ownerProvider);
return ( return (
<TableContainer> <TableContainer>
@ -35,12 +47,11 @@ export class AllDevices extends React.Component {
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell>Owner</TableCell> <TableCell>Owner</TableCell>
{showProviderCol && {showProviderCol && <TableCell>Auth Provider</TableCell>}
<TableCell>Auth Provider</TableCell>
}
<TableCell>Device</TableCell> <TableCell>Device</TableCell>
<TableCell>Connected</TableCell> <TableCell>Connected</TableCell>
<TableCell>Last Seen</TableCell> <TableCell>Last Seen</TableCell>
<TableCell>Actions</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
@ -49,12 +60,15 @@ export class AllDevices extends React.Component {
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
{row.ownerName || row.ownerEmail || row.owner} {row.ownerName || row.ownerEmail || row.owner}
</TableCell> </TableCell>
{showProviderCol && {showProviderCol && <TableCell>{row.ownerProvider}</TableCell>}
<TableCell>{row.ownerProvider}</TableCell>
}
<TableCell>{row.name}</TableCell> <TableCell>{row.name}</TableCell>
<TableCell>{row.connected ? 'yes' : 'no'}</TableCell> <TableCell>{row.connected ? 'yes' : 'no'}</TableCell>
<TableCell>{lastSeen(row.lastHandshakeTime)}</TableCell> <TableCell>{lastSeen(row.lastHandshakeTime)}</TableCell>
<TableCell>
<Button variant="outlined" color="secondary" onClick={() => this.deleteDevice(row)}>
Delete
</Button>
</TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>

File diff suppressed because it is too large Load Diff

@ -8,350 +8,329 @@ import * as grpcWeb from 'grpc-web';
import * as googleProtobufWrappers from 'google-protobuf/google/protobuf/wrappers_pb'; import * as googleProtobufWrappers from 'google-protobuf/google/protobuf/wrappers_pb';
export class Server { export class Server {
private client_ = new grpcWeb.GrpcWebClientBase({
private client_ = new grpcWeb.GrpcWebClientBase({ format: 'text',
format: 'text', });
});
private methodInfoInfo = new grpcWeb.AbstractClientBase.MethodInfo(
private methodInfoInfo = new grpcWeb.AbstractClientBase.MethodInfo( InfoRes,
InfoRes, (req: InfoReq) => req.serializeBinary(),
(req: InfoReq) => req.serializeBinary(), InfoRes.deserializeBinary,
InfoRes.deserializeBinary );
);
constructor(private hostname: string, private defaultMetadata?: () => grpcWeb.Metadata) {}
constructor(
private hostname: string, info(req: InfoReq.AsObject, metadata?: grpcWeb.Metadata): Promise<InfoRes.AsObject> {
private defaultMetadata?: () => grpcWeb.Metadata, return new Promise((resolve, reject) => {
) { } const message = InfoReqFromObject(req);
this.client_.rpcCall(
info(req: InfoReq.AsObject, metadata?: grpcWeb.Metadata): Promise<InfoRes.AsObject> { this.hostname + '/proto.Server/Info',
return new Promise((resolve, reject) => { message,
const message = InfoReqFromObject(req); Object.assign({}, this.defaultMetadata ? this.defaultMetadata() : {}, metadata),
this.client_.rpcCall( this.methodInfoInfo,
this.hostname + '/proto.Server/Info', (err: grpcWeb.Error, res: InfoRes) => {
message, if (err) {
Object.assign({}, this.defaultMetadata ? this.defaultMetadata() : {}, metadata), reject(err);
this.methodInfoInfo, } else {
(err: grpcWeb.Error, res: InfoRes) => { resolve(res.toObject());
if (err) { }
reject(err); },
} else { );
resolve(res.toObject()); });
} }
},
);
});
}
} }
export declare namespace InfoReq { export declare namespace InfoReq {
export type AsObject = { export type AsObject = {};
}
} }
export class InfoReq extends jspb.Message { export class InfoReq extends jspb.Message {
private static repeatedFields_ = [];
private static repeatedFields_ = [
constructor(data?: jspb.Message.MessageArray) {
]; super();
jspb.Message.initialize(this, data || [], 0, -1, InfoReq.repeatedFields_, null);
constructor(data?: jspb.Message.MessageArray) { }
super();
jspb.Message.initialize(this, data || [], 0, -1, InfoReq.repeatedFields_, null); serializeBinary(): Uint8Array {
} const writer = new jspb.BinaryWriter();
InfoReq.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
serializeBinary(): Uint8Array { }
const writer = new jspb.BinaryWriter();
InfoReq.serializeBinaryToWriter(this, writer); toObject(): InfoReq.AsObject {
return writer.getResultBuffer(); let f: any;
} return {};
}
toObject(): InfoReq.AsObject {
let f: any; static serializeBinaryToWriter(message: InfoReq, writer: jspb.BinaryWriter): void {}
return {
}; static deserializeBinary(bytes: Uint8Array): InfoReq {
} var reader = new jspb.BinaryReader(bytes);
var message = new InfoReq();
static serializeBinaryToWriter(message: InfoReq, writer: jspb.BinaryWriter): void { return InfoReq.deserializeBinaryFromReader(message, reader);
} }
static deserializeBinary(bytes: Uint8Array): InfoReq { static deserializeBinaryFromReader(message: InfoReq, reader: jspb.BinaryReader): InfoReq {
var reader = new jspb.BinaryReader(bytes); while (reader.nextField()) {
var message = new InfoReq(); if (reader.isEndGroup()) {
return InfoReq.deserializeBinaryFromReader(message, reader); break;
} }
const field = reader.getFieldNumber();
static deserializeBinaryFromReader(message: InfoReq, reader: jspb.BinaryReader): InfoReq { switch (field) {
while (reader.nextField()) { default:
if (reader.isEndGroup()) { reader.skipField();
break; break;
} }
const field = reader.getFieldNumber(); }
switch (field) { return message;
default: }
reader.skipField();
break;
}
}
return message;
}
} }
export declare namespace InfoRes { export declare namespace InfoRes {
export type AsObject = { export type AsObject = {
publicKey: string, publicKey: string;
host?: googleProtobufWrappers.StringValue.AsObject, host?: googleProtobufWrappers.StringValue.AsObject;
port: number, port: number;
hostVpnIp: string, hostVpnIp: string;
metadataEnabled: boolean, metadataEnabled: boolean;
isAdmin: boolean, isAdmin: boolean;
allowedIps: string, allowedIps: string;
dnsEnabled: boolean, dnsEnabled: boolean;
dnsAddress: string, dnsAddress: string;
} };
} }
export class InfoRes extends jspb.Message { export class InfoRes extends jspb.Message {
private static repeatedFields_ = [];
private static repeatedFields_ = [
constructor(data?: jspb.Message.MessageArray) {
]; super();
jspb.Message.initialize(this, data || [], 0, -1, InfoRes.repeatedFields_, null);
constructor(data?: jspb.Message.MessageArray) { }
super();
jspb.Message.initialize(this, data || [], 0, -1, InfoRes.repeatedFields_, null); getPublicKey(): string {
} return jspb.Message.getFieldWithDefault(this, 1, '');
}
getPublicKey(): string { setPublicKey(value: string): void {
return jspb.Message.getFieldWithDefault(this, 1, ""); (jspb.Message as any).setProto3StringField(this, 1, value);
} }
setPublicKey(value: string): void { getHost(): googleProtobufWrappers.StringValue {
(jspb.Message as any).setProto3StringField(this, 1, value); return jspb.Message.getWrapperField(this, googleProtobufWrappers.StringValue, 2);
} }
getHost(): googleProtobufWrappers.StringValue { setHost(value?: googleProtobufWrappers.StringValue): void {
return jspb.Message.getWrapperField(this, googleProtobufWrappers.StringValue, 2); (jspb.Message as any).setWrapperField(this, 2, value);
} }
setHost(value?: googleProtobufWrappers.StringValue): void { getPort(): number {
(jspb.Message as any).setWrapperField(this, 2, value); return jspb.Message.getFieldWithDefault(this, 3, 0);
} }
getPort(): number { setPort(value: number): void {
return jspb.Message.getFieldWithDefault(this, 3, 0); (jspb.Message as any).setProto3IntField(this, 3, value);
} }
setPort(value: number): void { getHostVpnIp(): string {
(jspb.Message as any).setProto3IntField(this, 3, value); return jspb.Message.getFieldWithDefault(this, 4, '');
} }
getHostVpnIp(): string { setHostVpnIp(value: string): void {
return jspb.Message.getFieldWithDefault(this, 4, ""); (jspb.Message as any).setProto3StringField(this, 4, value);
} }
setHostVpnIp(value: string): void { getMetadataEnabled(): boolean {
(jspb.Message as any).setProto3StringField(this, 4, value); return jspb.Message.getFieldWithDefault(this, 5, false);
} }
getMetadataEnabled(): boolean { setMetadataEnabled(value: boolean): void {
return jspb.Message.getFieldWithDefault(this, 5, false); (jspb.Message as any).setProto3BooleanField(this, 5, value);
} }
setMetadataEnabled(value: boolean): void { getIsAdmin(): boolean {
(jspb.Message as any).setProto3BooleanField(this, 5, value); return jspb.Message.getFieldWithDefault(this, 6, false);
} }
getIsAdmin(): boolean { setIsAdmin(value: boolean): void {
return jspb.Message.getFieldWithDefault(this, 6, false); (jspb.Message as any).setProto3BooleanField(this, 6, value);
} }
setIsAdmin(value: boolean): void { getAllowedIps(): string {
(jspb.Message as any).setProto3BooleanField(this, 6, value); return jspb.Message.getFieldWithDefault(this, 7, '');
} }
getAllowedIps(): string { setAllowedIps(value: string): void {
return jspb.Message.getFieldWithDefault(this, 7, ""); (jspb.Message as any).setProto3StringField(this, 7, value);
} }
setAllowedIps(value: string): void { getDnsEnabled(): boolean {
(jspb.Message as any).setProto3StringField(this, 7, value); return jspb.Message.getFieldWithDefault(this, 8, false);
} }
getDnsEnabled(): boolean { setDnsEnabled(value: boolean): void {
return jspb.Message.getFieldWithDefault(this, 8, false); (jspb.Message as any).setProto3BooleanField(this, 8, value);
} }
setDnsEnabled(value: boolean): void { getDnsAddress(): string {
(jspb.Message as any).setProto3BooleanField(this, 8, value); return jspb.Message.getFieldWithDefault(this, 9, '');
} }
getDnsAddress(): string { setDnsAddress(value: string): void {
return jspb.Message.getFieldWithDefault(this, 9, ""); (jspb.Message as any).setProto3StringField(this, 9, value);
} }
setDnsAddress(value: string): void { serializeBinary(): Uint8Array {
(jspb.Message as any).setProto3StringField(this, 9, value); const writer = new jspb.BinaryWriter();
} InfoRes.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
serializeBinary(): Uint8Array { }
const writer = new jspb.BinaryWriter();
InfoRes.serializeBinaryToWriter(this, writer); toObject(): InfoRes.AsObject {
return writer.getResultBuffer(); let f: any;
} return {
publicKey: this.getPublicKey(),
toObject(): InfoRes.AsObject { host: (f = this.getHost()) && f.toObject(),
let f: any; port: this.getPort(),
return {publicKey: this.getPublicKey(), hostVpnIp: this.getHostVpnIp(),
host: (f = this.getHost()) && f.toObject(), metadataEnabled: this.getMetadataEnabled(),
port: this.getPort(), isAdmin: this.getIsAdmin(),
hostVpnIp: this.getHostVpnIp(), allowedIps: this.getAllowedIps(),
metadataEnabled: this.getMetadataEnabled(), dnsEnabled: this.getDnsEnabled(),
isAdmin: this.getIsAdmin(), dnsAddress: this.getDnsAddress(),
allowedIps: this.getAllowedIps(), };
dnsEnabled: this.getDnsEnabled(), }
dnsAddress: this.getDnsAddress(),
static serializeBinaryToWriter(message: InfoRes, writer: jspb.BinaryWriter): void {
}; const field1 = message.getPublicKey();
} if (field1.length > 0) {
writer.writeString(1, field1);
static serializeBinaryToWriter(message: InfoRes, writer: jspb.BinaryWriter): void { }
const field1 = message.getPublicKey(); const field2 = message.getHost();
if (field1.length > 0) { if (field2 != null) {
writer.writeString(1, field1); writer.writeMessage(2, field2, googleProtobufWrappers.StringValue.serializeBinaryToWriter);
} }
const field2 = message.getHost(); const field3 = message.getPort();
if (field2 != null) { if (field3 != 0) {
writer.writeMessage(2, field2, googleProtobufWrappers.StringValue.serializeBinaryToWriter); writer.writeInt32(3, field3);
} }
const field3 = message.getPort(); const field4 = message.getHostVpnIp();
if (field3 != 0) { if (field4.length > 0) {
writer.writeInt32(3, field3); writer.writeString(4, field4);
} }
const field4 = message.getHostVpnIp(); const field5 = message.getMetadataEnabled();
if (field4.length > 0) { if (field5 != false) {
writer.writeString(4, field4); writer.writeBool(5, field5);
} }
const field5 = message.getMetadataEnabled(); const field6 = message.getIsAdmin();
if (field5 != false) { if (field6 != false) {
writer.writeBool(5, field5); writer.writeBool(6, field6);
} }
const field6 = message.getIsAdmin(); const field7 = message.getAllowedIps();
if (field6 != false) { if (field7.length > 0) {
writer.writeBool(6, field6); writer.writeString(7, field7);
} }
const field7 = message.getAllowedIps(); const field8 = message.getDnsEnabled();
if (field7.length > 0) { if (field8 != false) {
writer.writeString(7, field7); writer.writeBool(8, field8);
} }
const field8 = message.getDnsEnabled(); const field9 = message.getDnsAddress();
if (field8 != false) { if (field9.length > 0) {
writer.writeBool(8, field8); writer.writeString(9, field9);
} }
const field9 = message.getDnsAddress(); }
if (field9.length > 0) {
writer.writeString(9, field9); static deserializeBinary(bytes: Uint8Array): InfoRes {
} var reader = new jspb.BinaryReader(bytes);
} var message = new InfoRes();
return InfoRes.deserializeBinaryFromReader(message, reader);
static deserializeBinary(bytes: Uint8Array): InfoRes { }
var reader = new jspb.BinaryReader(bytes);
var message = new InfoRes(); static deserializeBinaryFromReader(message: InfoRes, reader: jspb.BinaryReader): InfoRes {
return InfoRes.deserializeBinaryFromReader(message, reader); while (reader.nextField()) {
} if (reader.isEndGroup()) {
break;
static deserializeBinaryFromReader(message: InfoRes, reader: jspb.BinaryReader): InfoRes { }
while (reader.nextField()) { const field = reader.getFieldNumber();
if (reader.isEndGroup()) { switch (field) {
break; case 1:
} const field1 = reader.readString();
const field = reader.getFieldNumber(); message.setPublicKey(field1);
switch (field) { break;
case 1: case 2:
const field1 = reader.readString() const field2 = new googleProtobufWrappers.StringValue();
message.setPublicKey(field1); reader.readMessage(field2, googleProtobufWrappers.StringValue.deserializeBinaryFromReader);
break; message.setHost(field2);
case 2: break;
const field2 = new googleProtobufWrappers.StringValue(); case 3:
reader.readMessage(field2, googleProtobufWrappers.StringValue.deserializeBinaryFromReader); const field3 = reader.readInt32();
message.setHost(field2); message.setPort(field3);
break; break;
case 3: case 4:
const field3 = reader.readInt32() const field4 = reader.readString();
message.setPort(field3); message.setHostVpnIp(field4);
break; break;
case 4: case 5:
const field4 = reader.readString() const field5 = reader.readBool();
message.setHostVpnIp(field4); message.setMetadataEnabled(field5);
break; break;
case 5: case 6:
const field5 = reader.readBool() const field6 = reader.readBool();
message.setMetadataEnabled(field5); message.setIsAdmin(field6);
break; break;
case 6: case 7:
const field6 = reader.readBool() const field7 = reader.readString();
message.setIsAdmin(field6); message.setAllowedIps(field7);
break; break;
case 7: case 8:
const field7 = reader.readString() const field8 = reader.readBool();
message.setAllowedIps(field7); message.setDnsEnabled(field8);
break; break;
case 8: case 9:
const field8 = reader.readBool() const field9 = reader.readString();
message.setDnsEnabled(field8); message.setDnsAddress(field9);
break; break;
case 9: default:
const field9 = reader.readString() reader.skipField();
message.setDnsAddress(field9); break;
break; }
default: }
reader.skipField(); return message;
break; }
}
}
return message;
}
} }
function InfoReqFromObject(obj: InfoReq.AsObject | undefined): InfoReq | undefined { function InfoReqFromObject(obj: InfoReq.AsObject | undefined): InfoReq | undefined {
if (obj === undefined) { if (obj === undefined) {
return undefined; return undefined;
} }
const message = new InfoReq(); const message = new InfoReq();
return message; return message;
} }
function InfoResFromObject(obj: InfoRes.AsObject | undefined): InfoRes | undefined { function InfoResFromObject(obj: InfoRes.AsObject | undefined): InfoRes | undefined {
if (obj === undefined) { if (obj === undefined) {
return undefined; return undefined;
} }
const message = new InfoRes(); const message = new InfoRes();
message.setPublicKey(obj.publicKey); message.setPublicKey(obj.publicKey);
message.setHost(StringValueFromObject(obj.host)); message.setHost(StringValueFromObject(obj.host));
message.setPort(obj.port); message.setPort(obj.port);
message.setHostVpnIp(obj.hostVpnIp); message.setHostVpnIp(obj.hostVpnIp);
message.setMetadataEnabled(obj.metadataEnabled); message.setMetadataEnabled(obj.metadataEnabled);
message.setIsAdmin(obj.isAdmin); message.setIsAdmin(obj.isAdmin);
message.setAllowedIps(obj.allowedIps); message.setAllowedIps(obj.allowedIps);
message.setDnsEnabled(obj.dnsEnabled); message.setDnsEnabled(obj.dnsEnabled);
message.setDnsAddress(obj.dnsAddress); message.setDnsAddress(obj.dnsAddress);
return message; return message;
} }
function StringValueFromObject(obj: googleProtobufWrappers.StringValue.AsObject | undefined): googleProtobufWrappers.StringValue | undefined { function StringValueFromObject(
if (obj === undefined) { obj: googleProtobufWrappers.StringValue.AsObject | undefined,
return undefined; ): googleProtobufWrappers.StringValue | undefined {
} if (obj === undefined) {
const message = new googleProtobufWrappers.StringValue(); return undefined;
message.setValue(obj.value); }
return message; const message = new googleProtobufWrappers.StringValue();
message.setValue(obj.value);
return message;
} }

Loading…
Cancel
Save