From ac74c122e0399c1c47580c72c9de994d36950e55 Mon Sep 17 00:00:00 2001 From: Mike Cousins Date: Wed, 6 Nov 2019 12:46:54 -0500 Subject: [PATCH] feat(app): parse subnest out of CIDR-notation IP address (#4372) Closes #4075 --- app/package.json | 1 + .../components/RobotSettings/connection.js | 11 +++-- .../__tests__/networking.test.js | 6 ++- app/src/http-api-client/networking.js | 40 +++++++++++++++++-- yarn.lock | 5 +++ 5 files changed, 54 insertions(+), 9 deletions(-) diff --git a/app/package.json b/app/package.json index 1923029759e..59e5bdcc711 100644 --- a/app/package.json +++ b/app/package.json @@ -34,6 +34,7 @@ "lodash": "^4.17.4", "mixpanel-browser": "^2.22.1", "moment": "^2.19.1", + "netmask": "^1.0.6", "path-to-regexp": "^3.0.0", "react": "^16.8.6", "react-dom": "^16.8.6", diff --git a/app/src/components/RobotSettings/connection.js b/app/src/components/RobotSettings/connection.js index 4e41152daba..0744d5601fb 100644 --- a/app/src/components/RobotSettings/connection.js +++ b/app/src/components/RobotSettings/connection.js @@ -77,8 +77,9 @@ type NetworkAddressProps = { function NetworkAddresses(props: NetworkAddressProps) { const type = props.wired ? 'Wired' : 'Wireless' - const ip = (props.connection && props.connection.ipAddress) || 'Unknown' - const mac = (props.connection && props.connection.macAddress) || 'Unknown' + const ip = props.connection?.ipAddress || 'Unknown' + const subnet = props.connection?.subnetMask || 'Unknown' + const mac = props.connection?.macAddress || 'Unknown' const labelStyles = cx(styles.connection_label, { [styles.disabled]: props.disabled, }) @@ -90,7 +91,11 @@ function NetworkAddresses(props: NetworkAddressProps) { {ip}

- {type} MAC address: + {type} Subnet Mask: + {subnet} +

+

+ {type} MAC Address: {mac}

diff --git a/app/src/http-api-client/__tests__/networking.test.js b/app/src/http-api-client/__tests__/networking.test.js index 3354d0aa682..8db5f46b02a 100644 --- a/app/src/http-api-client/__tests__/networking.test.js +++ b/app/src/http-api-client/__tests__/networking.test.js @@ -22,13 +22,15 @@ describe('networking', () => { api: { api: { someName: { - 'networking/status': { response: { status: 'full' } }, + 'networking/status': { + response: { status: 'full', interfaces: {} }, + }, }, }, }, }, props: { name: 'someName' }, - expected: { response: { status: 'full' } }, + expected: { response: { status: 'full', interfaces: {} } }, }, { name: 'makeGetRobotWifiList', diff --git a/app/src/http-api-client/networking.js b/app/src/http-api-client/networking.js index 53650ae43b4..7cf7bf16a00 100644 --- a/app/src/http-api-client/networking.js +++ b/app/src/http-api-client/networking.js @@ -1,9 +1,11 @@ // @flow // networking http api module import { createSelector } from 'reselect' +import mapValues from 'lodash/mapValues' import orderBy from 'lodash/orderBy' import partition from 'lodash/partition' import uniqBy from 'lodash/uniqBy' +import { Netmask } from 'netmask' import { apiRequest, @@ -32,13 +34,17 @@ export type InternetStatus = 'none' | 'portal' | 'limited' | 'full' | 'unknown' export type WifiSecurityType = 'none' | 'wpa-psk' | 'wpa-eap' -export type NetworkInterface = { +// TODO(mc, 2019-11-5): this does not match the response shape +// the shape change happens in the selector, but should be happening +// in the reducer. THis will be fixed when http-api-client is gone +export type NetworkInterface = {| ipAddress: ?string, + subnetMask: ?string, macAddress: string, gatewayAddress: ?string, state: string, type: 'wifi' | 'ethernet', -} +|} export type WifiNetwork = { ssid: string, @@ -198,8 +204,34 @@ type GetConfigureWifiCall = Sel export const makeGetRobotNetworkingStatus = (): GetNetworkingStatusCall => createSelector( getRobotApiState, - // $FlowFixMe: (mc, 2019-04-18) http-api-client types need to be redone - state => state[STATUS] || { inProgress: false } + state => { + // $FlowFixMe: (mc, 2019-04-18) http-api-client types need to be redone + const statusCall = state[STATUS] || { inProgress: false } + if (!statusCall.response) return statusCall + + return { + ...statusCall, + response: { + ...statusCall.response, + interfaces: mapValues(statusCall.response.interfaces, iface => { + let ipAddress = null + let subnetMask = null + if (iface.ipAddress != null) { + try { + const block = new Netmask(iface.ipAddress) + ipAddress = block.base + subnetMask = block.mask + } catch (e) { + // just use what was passed if unable to parse + ipAddress = iface.ipAddress + } + } + + return { ...iface, ipAddress, subnetMask } + }), + }, + } + } ) export const makeGetRobotWifiList = (): GetWifiListCall => diff --git a/yarn.lock b/yarn.lock index 7596fcb16ac..c3c7c913f25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11493,6 +11493,11 @@ neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== +netmask@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" + integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU= + nice-try@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4"