diff --git a/CHANGELOG.md b/CHANGELOG.md index b49c2a3e01..4adb139bfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,19 +14,17 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// # [v1.1.9] (2023-02-07) ### Added - -- Separate `nym-api` endpoints with values of "total-supply" and "circulating-supply" in `nym` ([#2964]) -- Add `host` option to client init ([#2912]) - Remove Coconut feature flag ([#2793]) -- Don't drop in mixnet connection handler ([#2963]) +- Separate `nym-api` endpoints with values of "total-supply" and "circulating-supply" in `nym` ([#2964]) ### Changed -- native-client: is now capable of listening for requests on sockets different than `127.0.0.1` ([#2939]). This can be specified via `--host` flag during `init` or `run`. Alternatively a custom `host` can be set in `config.toml` file under `socket` section. +- native-client: is now capable of listening for requests on sockets different than `127.0.0.1` ([#2912]). This can be specified via `--host` flag during `init` or `run`. Alternatively a custom `host` can be set in `config.toml` file under `socket` section. - mixnode, gateway: fix unexpected shutdown on corrupted connection ([#2963]) -[#2939]: https://github.com/nymtech/nym/pull/2939 -[#2963]: https://github.com/nymtech/nym/pull/2963 - +[#2793]: https://github.com/nymtech/nym/issues/2793 +[#2912]: https://github.com/nymtech/nym/issues/2912 +[#2964]: https://github.com/nymtech/nym/issues/2964 +[#2963]: https://github.com/nymtech/nym/issues/3017 # [v1.1.8] (2023-01-31) diff --git a/Cargo.lock b/Cargo.lock index 99b80c3f19..221d61b181 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -693,7 +693,7 @@ dependencies = [ [[package]] name = "client-core" -version = "1.1.8" +version = "1.1.9" dependencies = [ "async-trait", "client-connections", @@ -1885,7 +1885,7 @@ dependencies = [ [[package]] name = "explorer-api" -version = "1.1.8" +version = "1.1.9" dependencies = [ "chrono", "clap 4.1.4", @@ -3425,7 +3425,7 @@ dependencies = [ [[package]] name = "nym-api" -version = "1.1.9" +version = "1.1.10" dependencies = [ "anyhow", "async-trait", @@ -3523,7 +3523,7 @@ dependencies = [ [[package]] name = "nym-cli" -version = "1.1.8" +version = "1.1.9" dependencies = [ "anyhow", "base64 0.13.1", @@ -3581,7 +3581,7 @@ dependencies = [ [[package]] name = "nym-client" -version = "1.1.8" +version = "1.1.9" dependencies = [ "build-information", "clap 4.1.4", @@ -3621,7 +3621,7 @@ dependencies = [ [[package]] name = "nym-gateway" -version = "1.1.8" +version = "1.1.9" dependencies = [ "anyhow", "async-trait", @@ -3673,7 +3673,7 @@ dependencies = [ [[package]] name = "nym-mixnode" -version = "1.1.9" +version = "1.1.10" dependencies = [ "anyhow", "atty", @@ -3718,7 +3718,7 @@ dependencies = [ [[package]] name = "nym-network-requester" -version = "1.1.8" +version = "1.1.9" dependencies = [ "async-trait", "build-information", @@ -3752,7 +3752,7 @@ dependencies = [ [[package]] name = "nym-network-statistics" -version = "1.1.8" +version = "1.1.9" dependencies = [ "dirs", "log", @@ -3809,7 +3809,7 @@ dependencies = [ [[package]] name = "nym-socks5-client" -version = "1.1.8" +version = "1.1.9" dependencies = [ "build-information", "clap 4.1.4", diff --git a/clients/client-core/Cargo.toml b/clients/client-core/Cargo.toml index f9802bc367..5196587ba7 100644 --- a/clients/client-core/Cargo.toml +++ b/clients/client-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "client-core" -version = "1.1.8" +version = "1.1.9" authors = ["Dave Hrycyszyn "] edition = "2021" rust-version = "1.66" diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index 255c89da61..df2f9dad8d 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-client" -version = "1.1.8" +version = "1.1.9" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] description = "Implementation of the Nym Client" edition = "2021" diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index e1a186d9ed..49bbc93119 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-socks5-client" -version = "1.1.8" +version = "1.1.9" authors = ["Dave Hrycyszyn "] description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" edition = "2021" diff --git a/explorer-api/Cargo.toml b/explorer-api/Cargo.toml index 5d09ccb5c3..dcfc34eb35 100644 --- a/explorer-api/Cargo.toml +++ b/explorer-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "explorer-api" -version = "1.1.8" +version = "1.1.9" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/explorer/CHANGELOG.md b/explorer/CHANGELOG.md index 0098db042d..5d5a40da22 100644 --- a/explorer/CHANGELOG.md +++ b/explorer/CHANGELOG.md @@ -2,7 +2,7 @@ - nothing yet -## [nym-explorer-v1.0.5](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.5) (2023-02-07) +## [nym-explorer-v1.0.5](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.5) (2023-02-14) - NE - link `Owner` field on the node detail page to the account details on NG explorer ([#2923]) - NE - Upgrade Sandbox and make below changes: ([#2332]) diff --git a/explorer/package.json b/explorer/package.json index c4b82c7a78..f2ca75b38b 100644 --- a/explorer/package.json +++ b/explorer/package.json @@ -1,6 +1,6 @@ { "name": "@nym/network-explorer", - "version": "1.0.4", + "version": "1.0.5", "private": true, "license": "Apache-2.0", "dependencies": { diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index 5b1fd14ccf..52d4f36733 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-gateway" -version = "1.1.8" +version = "1.1.9" authors = [ "Dave Hrycyszyn ", "Jędrzej Stuczyński ", diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index 18521daf35..66a21d7038 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-mixnode" -version = "1.1.9" +version = "1.1.10" authors = [ "Dave Hrycyszyn ", "Jędrzej Stuczyński ", diff --git a/nym-api/Cargo.toml b/nym-api/Cargo.toml index 6db7cfa812..6378976a15 100644 --- a/nym-api/Cargo.toml +++ b/nym-api/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-api" -version = "1.1.9" +version = "1.1.10" authors = [ "Dave Hrycyszyn ", "Jędrzej Stuczyński ", diff --git a/nym-connect/CHANGELOG.md b/nym-connect/CHANGELOG.md index 39b13e201f..7c67f24f36 100644 --- a/nym-connect/CHANGELOG.md +++ b/nym-connect/CHANGELOG.md @@ -1,12 +1,16 @@ # Changelog -## [nym-connect-v1.1.9](https://github.com/nymtech/nym/tree/nym-connect-v1.1.9) (2023-02-07) +## UNRELEASED -- NC - Button animations ([#2949]) -- NC - add effect when the button is clicked ([#2947]) -- NC - UI to select gateways based on some performance criteria by checking gateways' routing score from nym-api ([#2942]) -- NC - client health check when connecting ([#2859]) +## [nym-connect-v1.1.9](https://github.com/nymtech/nym/tree/nym-connect-v1.1.9) (2023-02-14) +- Button animations ([#2949]) +- add effect when the button is clicked ([#2947]) +- UI to select gateways based on some performance criteria by checking gateways' routing score from nym-api ([#2942]) +- client health check when connecting ([#2859]) +- allow user to select own gateway ([#2952]) + +[#2952]: https://github.com/nymtech/nym/issues/2952 [#2949]: https://github.com/nymtech/nym/issues/2949 [#2947]: https://github.com/nymtech/nym/issues/2947 [#2942]: https://github.com/nymtech/nym/issues/2942 diff --git a/nym-connect/package.json b/nym-connect/package.json index 127ac38de1..b124d71730 100644 --- a/nym-connect/package.json +++ b/nym-connect/package.json @@ -1,6 +1,6 @@ { "name": "@nym/nym-connect", - "version": "1.1.8", + "version": "1.1.9", "main": "index.js", "license": "MIT", "scripts": { diff --git a/nym-connect/src-tauri/Cargo.toml b/nym-connect/src-tauri/Cargo.toml index 93e21710bb..d80662fd18 100644 --- a/nym-connect/src-tauri/Cargo.toml +++ b/nym-connect/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-connect" -version = "1.1.8" +version = "1.1.9" description = "nym-connect" authors = ["Nym Technologies SA"] license = "" diff --git a/nym-connect/src-tauri/tauri.conf.json b/nym-connect/src-tauri/tauri.conf.json index deff29513f..8642c2e26c 100644 --- a/nym-connect/src-tauri/tauri.conf.json +++ b/nym-connect/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "package": { "productName": "nym-connect", - "version": "1.1.8" + "version": "1.1.9" }, "build": { "distDir": "../dist", diff --git a/nym-connect/src/components/AppWindowFrame.tsx b/nym-connect/src/components/AppWindowFrame.tsx index 4b407c3e7b..929b0f269f 100644 --- a/nym-connect/src/components/AppWindowFrame.tsx +++ b/nym-connect/src/components/AppWindowFrame.tsx @@ -1,10 +1,28 @@ import React from 'react'; import { Box } from '@mui/material'; import { useLocation } from 'react-router-dom'; +import { useClientContext } from 'src/context/main'; import { CustomTitleBar } from './CustomTitleBar'; export const AppWindowFrame: FCWithChildren = ({ children }) => { const location = useLocation(); + const { userDefinedGateway, setUserDefinedGateway } = useClientContext(); + + // defined functions to be used when moving away from pages + const onBack = () => { + switch (location.pathname) { + case '/menu/settings': + return () => { + // when the user moves away from the settings page and the gateway is not valid + // set isActive to false + if (!userDefinedGateway?.gateway) { + setUserDefinedGateway((current) => ({ ...current, isActive: false })); + } + }; + default: + return undefined; + } + }; return ( { height: '100vh', }} > - + {children} ); diff --git a/nym-connect/src/components/CustomTitleBar.tsx b/nym-connect/src/components/CustomTitleBar.tsx index e7d81aecfa..d88b603873 100644 --- a/nym-connect/src/components/CustomTitleBar.tsx +++ b/nym-connect/src/components/CustomTitleBar.tsx @@ -29,9 +29,13 @@ const MenuIcon = () => { return navigate('/menu')} />; }; -const ArrowBackIcon = () => { +const ArrowBackIcon = ({ onBack }: { onBack?: () => void }) => { const navigate = useNavigate(); - return navigate(-1)} />; + const handleBack = () => { + onBack?.(); + navigate(-1); + }; + return ; }; const getTitleIcon = (path: string) => { @@ -46,10 +50,10 @@ const getTitleIcon = (path: string) => { return ; }; -export const CustomTitleBar = ({ path = '/' }: { path?: string }) => ( +export const CustomTitleBar = ({ path = '/', onBack }: { path?: string; onBack?: () => void }) => ( {/* set width to keep logo centered */} - {path === '/' ? : } + {path === '/' ? : } {getTitleIcon(path)} appWindow.minimize()} /> diff --git a/nym-connect/src/context/main.tsx b/nym-connect/src/context/main.tsx index 8c02df4e41..a933a8c36f 100644 --- a/nym-connect/src/context/main.tsx +++ b/nym-connect/src/context/main.tsx @@ -4,10 +4,14 @@ import { invoke } from '@tauri-apps/api'; import { Error } from 'src/types/error'; import { getVersion } from '@tauri-apps/api/app'; import { useEvents } from 'src/hooks/events'; +import { UserDefinedGateway } from 'src/types/gateway'; +import { forage } from '@tauri-apps/tauri-forage'; import { ConnectionStatusKind, GatewayPerformance } from '../types'; import { ConnectionStatsItem } from '../components/ConnectionStats'; import { ServiceProvider } from '../types/directory'; +const FORAGE_KEY = 'nym-connect-user-gateway'; + type ModeType = 'light' | 'dark'; export type TClientContext = { @@ -20,6 +24,7 @@ export type TClientContext = { gatewayPerformance: GatewayPerformance; selectedProvider?: ServiceProvider; showInfoModal: boolean; + userDefinedGateway?: UserDefinedGateway; setMode: (mode: ModeType) => void; clearError: () => void; setConnectionStatus: (connectionStatus: ConnectionStatusKind) => void; @@ -29,6 +34,7 @@ export type TClientContext = { setRandomSerivceProvider: () => void; startConnecting: () => Promise; startDisconnecting: () => Promise; + setUserDefinedGateway: React.Dispatch>; }; export const ClientContext = createContext({} as TClientContext); @@ -44,19 +50,43 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => { const [appVersion, setAppVersion] = useState(); const [gatewayPerformance, setGatewayPerformance] = useState('Good'); const [showInfoModal, setShowInfoModal] = useState(false); + const [userDefinedGateway, setUserDefinedGateway] = useState({ isActive: false, gateway: '' }); const getAppVersion = async () => { const version = await getVersion(); return version; }; + const setUserGatewayInStorage = async (gateway: UserDefinedGateway) => { + try { + await forage.setItem({ + key: FORAGE_KEY, + value: gateway, + } as any)(); + } catch (e) { + console.warn(e); + } + return undefined; + }; + + const getUserGatewayFromStorage = async (): Promise => { + try { + const gatewayFromStorage = await forage.getItem({ key: FORAGE_KEY })(); + return gatewayFromStorage; + } catch (e) { + console.warn(e); + } + return undefined; + }; + const initialiseApp = async () => { const services = await invoke('get_services'); const AppVersion = await getAppVersion(); - console.log(services); + const storedUserDefinedGateway = await getUserGatewayFromStorage(); setAppVersion(AppVersion); setServiceProviders(services as ServiceProvider[]); + if (storedUserDefinedGateway) setUserDefinedGateway(storedUserDefinedGateway); }; useEvents({ @@ -94,15 +124,19 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => { } }, []); - const setServiceProvider = async (newServiceProvider?: ServiceProvider) => { - if (newServiceProvider) { - await invoke('set_gateway', { gateway: newServiceProvider.gateway }); - await invoke('set_service_provider', { serviceProvider: newServiceProvider.address }); - } + const shouldUseUserGateway = !!userDefinedGateway.gateway && userDefinedGateway.isActive; + + const setServiceProvider = async (newServiceProvider: ServiceProvider) => { + await invoke('set_gateway', { + gateway: newServiceProvider.gateway, + }); + await invoke('set_service_provider', { serviceProvider: newServiceProvider.address }); }; const getRandomSPFromList = (services: ServiceProvider[]) => { const randomSelection = services[Math.floor(Math.random() * services.length)]; + + if (shouldUseUserGateway) return { ...randomSelection, gateway: userDefinedGateway.gateway } as ServiceProvider; return randomSelection; }; @@ -110,8 +144,10 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => { if (serviceProviders) { const randomServiceProvider = getRandomSPFromList(serviceProviders); await setServiceProvider(randomServiceProvider); + await setUserGatewayInStorage(userDefinedGateway); setSelectedProvider(randomServiceProvider); } + return undefined; }; const clearError = () => setError(undefined); @@ -136,6 +172,8 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => { startDisconnecting, gatewayPerformance, setShowInfoModal, + userDefinedGateway, + setUserDefinedGateway, }), [ mode, @@ -148,6 +186,7 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => { connectedSince, gatewayPerformance, selectedProvider, + userDefinedGateway, ], ); diff --git a/nym-connect/src/context/mocks/main.tsx b/nym-connect/src/context/mocks/main.tsx index ea86bb365d..6d0f7d9a82 100644 --- a/nym-connect/src/context/mocks/main.tsx +++ b/nym-connect/src/context/mocks/main.tsx @@ -9,6 +9,7 @@ const mockValues: TClientContext = { selectedProvider: { id: '1', description: 'Keybase service provider', gateway: 'abc123', address: '123abc' }, gatewayPerformance: 'Good', showInfoModal: false, + userDefinedGateway: { isActive: false, gateway: '' }, setShowInfoModal: () => {}, setMode: () => {}, clearError: () => {}, @@ -18,6 +19,7 @@ const mockValues: TClientContext = { startConnecting: async () => {}, startDisconnecting: async () => {}, setRandomSerivceProvider: () => {}, + setUserDefinedGateway: () => {}, }; export const MockProvider: FCWithChildren<{ diff --git a/nym-connect/src/pages/menu/Settings.tsx b/nym-connect/src/pages/menu/Settings.tsx new file mode 100644 index 0000000000..bc3716d20e --- /dev/null +++ b/nym-connect/src/pages/menu/Settings.tsx @@ -0,0 +1,85 @@ +import React, { ChangeEvent, useState } from 'react'; +import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'; +import { Box, FormControl, FormControlLabel, FormHelperText, Link, Stack, Switch, Typography } from '@mui/material'; +import { useClientContext } from 'src/context/main'; +import { ConnectionStatusKind } from 'src/types'; +import { AppVersion } from 'src/components/AppVersion'; + +export const Settings = () => { + const { userDefinedGateway, setUserDefinedGateway } = useClientContext(); + const [gatewayKey, setGatewayKey] = useState(userDefinedGateway?.gateway); + + const handleIsValidGatewayKey = (isValid: boolean) => { + let gateway: string | undefined; + + if (isValid) { + gateway = gatewayKey; + } + + setUserDefinedGateway((current) => ({ ...current, gateway })); + }; + + const handleChange = (e: ChangeEvent) => { + setUserDefinedGateway((current) => ({ ...current, isActive: e.target.checked })); + }; + + const { connectionStatus } = useClientContext(); + + return ( + + + + + Select your Gateway + + + Use a gateway of your choice + + + + } + label={userDefinedGateway?.isActive ? 'On' : 'Off'} + /> + {connectionStatus === ConnectionStatusKind.connected && ( + This setting is disabled during an active connection + )} + {userDefinedGateway?.isActive && ( + + )} + + + + + To find a gateway go to the{' '} + + Network Explorer + + + + + + + ); +}; diff --git a/nym-connect/src/pages/menu/index.tsx b/nym-connect/src/pages/menu/index.tsx index a4cac1bf20..67b3dc0131 100644 --- a/nym-connect/src/pages/menu/index.tsx +++ b/nym-connect/src/pages/menu/index.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Apps, HelpOutline } from '@mui/icons-material'; +import { Apps, HelpOutline, Settings } from '@mui/icons-material'; import { Stack, Link, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'; import { Link as RouterLink } from 'react-router-dom'; import { AppVersion } from 'src/components/AppVersion'; @@ -7,13 +7,14 @@ import { AppVersion } from 'src/components/AppVersion'; const menuSchema = [ { title: 'Supported apps', icon: Apps, path: 'apps' }, { title: 'How to connect guide', icon: HelpOutline, path: 'guide' }, + { title: 'Settings', icon: Settings, path: 'settings' }, ]; export const Menu = () => ( {menuSchema.map((item) => ( - + diff --git a/nym-connect/src/routes/index.tsx b/nym-connect/src/routes/index.tsx index ffb0881876..ec24080c6c 100644 --- a/nym-connect/src/routes/index.tsx +++ b/nym-connect/src/routes/index.tsx @@ -4,6 +4,7 @@ import { ConnectionPage } from 'src/pages/connection'; import { Menu } from 'src/pages/menu'; import { CompatibleApps } from 'src/pages/menu/Apps'; import { HelpGuide } from 'src/pages/menu/Guide'; +import { Settings } from 'src/pages/menu/Settings'; export const AppRoutes = () => ( @@ -12,6 +13,7 @@ export const AppRoutes = () => ( } /> } /> } /> + } /> ); diff --git a/nym-connect/src/theme/mui-theme.d.ts b/nym-connect/src/theme/mui-theme.d.ts index 6c4d88fe39..76db4b1a99 100644 --- a/nym-connect/src/theme/mui-theme.d.ts +++ b/nym-connect/src/theme/mui-theme.d.ts @@ -29,6 +29,7 @@ declare module '@mui/material/styles' { */ interface NymPalette { highlight: string; + cta: string; success: string; warning: string; info: string; diff --git a/nym-connect/src/theme/theme.tsx b/nym-connect/src/theme/theme.tsx index 18678fce98..977b0c9dfd 100644 --- a/nym-connect/src/theme/theme.tsx +++ b/nym-connect/src/theme/theme.tsx @@ -21,6 +21,7 @@ import { const nymPalette: NymPalette = { /** emphasises important elements */ highlight: '#21D072', + cta: '#FB6E4E', success: '#21D073', info: '#60D7EF', warning: '#FFE600', diff --git a/nym-connect/src/types/gateway.ts b/nym-connect/src/types/gateway.ts new file mode 100644 index 0000000000..735a3cdb03 --- /dev/null +++ b/nym-connect/src/types/gateway.ts @@ -0,0 +1,4 @@ +export interface UserDefinedGateway { + isActive: boolean; + gateway?: string; +} diff --git a/nym-wallet/CHANGELOG.md b/nym-wallet/CHANGELOG.md index 6cff0c274a..8dd815a758 100644 --- a/nym-wallet/CHANGELOG.md +++ b/nym-wallet/CHANGELOG.md @@ -2,6 +2,17 @@ ## UNRELEASED +## [nym-wallet-v1.1.9](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.1.9) (2023-02-14) + +- Allow more flexibility for user when setting passwords ([#2993]) +- User feedback on weak passwords ([#2993]) +- User no longer has to copy mnemonic to continune account creation ([#2948]) +- Updated instructional steps for creating accounts with a password ([#2962]) + +[#2948]: https://github.com/nymtech/nym/issues/2948 +[#2993]: https://github.com/nymtech/nym/issues/2993 +[#2962]: https://github.com/nymtech/nym/issues/2962 + ## [nym-wallet-v1.1.8](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.1.8) (2023-01-24) - Fix delegations sorting ([#2885]) diff --git a/nym-wallet/package.json b/nym-wallet/package.json index 9dc201f639..b1eda933fd 100644 --- a/nym-wallet/package.json +++ b/nym-wallet/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/nym-wallet-app", - "version": "1.1.8", + "version": "1.1.9", "main": "index.js", "license": "MIT", "scripts": { @@ -52,7 +52,8 @@ "string-to-color": "^2.2.2", "use-clipboard-copy": "^0.2.0", "uuid": "^8.3.2", - "yup": "^0.32.9" + "yup": "^0.32.9", + "zxcvbn": "^4.4.2" }, "devDependencies": { "@babel/core": "^7.15.0", @@ -76,6 +77,7 @@ "@types/react-dom": "^18.0.10", "@types/semver": "^7.3.8", "@types/uuid": "^8.3.4", + "@types/zxcvbn": "^4.4.1", "@typescript-eslint/eslint-plugin": "^5.13.0", "@typescript-eslint/parser": "^5.13.0", "babel-loader": "^8.3.0", @@ -120,4 +122,4 @@ "webpack-favicons": "^1.3.8", "webpack-merge": "^5.8.0" } -} +} \ No newline at end of file diff --git a/nym-wallet/src-tauri/Cargo.toml b/nym-wallet/src-tauri/Cargo.toml index fe3d203aa9..1be9d6eb28 100644 --- a/nym-wallet/src-tauri/Cargo.toml +++ b/nym-wallet/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym_wallet" -version = "1.1.8" +version = "1.1.9" description = "Nym Native Wallet" authors = ["Nym Technologies SA"] license = "" diff --git a/nym-wallet/src-tauri/tauri.conf.json b/nym-wallet/src-tauri/tauri.conf.json index 08cc4b3383..8b14c1d304 100644 --- a/nym-wallet/src-tauri/tauri.conf.json +++ b/nym-wallet/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "package": { "productName": "nym-wallet", - "version": "1.1.8" + "version": "1.1.9" }, "build": { "distDir": "../dist", @@ -14,7 +14,13 @@ "active": true, "targets": "all", "identifier": "net.nymtech.wallet", - "icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], "resources": [], "externalBin": [], "copyright": "Copyright © 2021-2022 Nym Technologies SA", @@ -27,7 +33,6 @@ "macOS": { "frameworks": [], "minimumSystemVersion": "", - "exceptionDomain": "", "signingIdentity": "Developer ID Application: Nym Technologies SA (VW5DZLFHM5)", "entitlements": null @@ -40,7 +45,9 @@ }, "updater": { "active": true, - "endpoints": ["https://nymtech.net/.wellknown/wallet/updater.json"], + "endpoints": [ + "https://nymtech.net/.wellknown/wallet/updater.json" + ], "dialog": true, "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IENCNzQ2M0E5N0VFODE2NApSV1JrZ2U2WE9rYTNETTg1OTBKdE5uWUEra0hML2syOVUvQ2lxZmFZRzZ1T3NWbGM0eVRzUTVhVwo=" }, @@ -67,4 +74,4 @@ "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'" } } -} +} \ No newline at end of file diff --git a/nym-wallet/src/components/Accounts/MultiAccountHowTo.tsx b/nym-wallet/src/components/Accounts/MultiAccountHowTo.tsx index c23f392bbe..62eb3a4643 100644 --- a/nym-wallet/src/components/Accounts/MultiAccountHowTo.tsx +++ b/nym-wallet/src/components/Accounts/MultiAccountHowTo.tsx @@ -5,11 +5,12 @@ import { SimpleModal } from '../Modals/SimpleModal'; import { Warning } from '../Warning'; const passwordCreationSteps = [ - 'Log out of your wallet', + 'Log out from the wallet', 'Sign in using “Sign in with mnemonic” button', - 'On the next screen select “Create a password for your account”', - 'Sign in to the wallet with your new password', - 'Then come back here to import or create new accounts', + 'On the next screen select “Create a password"', + 'Type in the mnemonic you want to create a password for and follow the next steps', + 'Sign back in the wallet using your new password', + 'Come back to this page to import or create new accounts', ]; // TODO add the link href value diff --git a/nym-wallet/src/components/Accounts/modals/AddAccountModal.tsx b/nym-wallet/src/components/Accounts/modals/AddAccountModal.tsx index 61d6f7b9e5..ac2132e636 100644 --- a/nym-wallet/src/components/Accounts/modals/AddAccountModal.tsx +++ b/nym-wallet/src/components/Accounts/modals/AddAccountModal.tsx @@ -10,7 +10,6 @@ import { TextField, Typography, } from '@mui/material'; -import { useClipboard } from 'use-clipboard-copy'; import { createMnemonic, validateMnemonic } from 'src/requests'; import { Console } from 'src/utils/console'; import { AccountsContext } from 'src/context'; @@ -30,16 +29,16 @@ const importAccountSteps = [ ]; const MnemonicStep = ({ mnemonic, onNext, onBack }: { mnemonic: string; onNext: () => void; onBack: () => void }) => { - const { copy, copied } = useClipboard({ copiedTimeout: 5000 }); + const [confirmed, setConfirmed] = useState(false); return ( - + - diff --git a/nym-wallet/src/components/Accounts/modals/MnemonicModal.tsx b/nym-wallet/src/components/Accounts/modals/MnemonicModal.tsx index c9ea2202a3..e2d6e02c2a 100644 --- a/nym-wallet/src/components/Accounts/modals/MnemonicModal.tsx +++ b/nym-wallet/src/components/Accounts/modals/MnemonicModal.tsx @@ -11,15 +11,12 @@ import { Typography, } from '@mui/material'; import { AccountsContext } from 'src/context'; -import { useClipboard } from 'use-clipboard-copy'; import { Mnemonic, PasswordInput } from 'src/components'; import { StyledBackButton } from 'src/components/StyledBackButton'; export const MnemonicModal = () => { const [password, setPassword] = useState(''); - const { copy, copied } = useClipboard({ copiedTimeout: 5000 }); - const { dialogToDisplay, setDialogToDisplay, @@ -72,7 +69,7 @@ export const MnemonicModal = () => { /> ) : ( - + )} diff --git a/nym-wallet/src/components/Mnemonic.tsx b/nym-wallet/src/components/Mnemonic.tsx index d445172e9a..7e592c1902 100644 --- a/nym-wallet/src/components/Mnemonic.tsx +++ b/nym-wallet/src/components/Mnemonic.tsx @@ -1,23 +1,32 @@ import React from 'react'; -import { Button, Stack, TextField, Typography } from '@mui/material'; -import { Check, ContentCopySharp } from '@mui/icons-material'; +import { Box, Checkbox, FormControlLabel, Stack, TextField, Typography } from '@mui/material'; +import { Title } from 'src/pages/auth/components/heading'; import { Warning } from './Warning'; export const Mnemonic = ({ mnemonic, - copied, - handleCopy, + confirmed, + withTitle, + handleConfirmed, }: { mnemonic: string; - copied: boolean; - handleCopy: (text?: string) => void; + confirmed?: boolean; + withTitle?: boolean; + handleConfirmed?: (confirmed: boolean) => void; }) => ( - - - - Below is your 24 word mnemonic, make sure to store it in a safe place for accessing your wallet in the future - - + + {withTitle && ( + + + </Box> + )} + <Box sx={{ pb: 2 }}> + <Warning> + <Typography sx={{ textAlign: 'center' }}> + Below is your 24 word mnemonic, make sure to store it in a safe place for accessing your wallet in the future + </Typography> + </Warning> + </Box> <TextField label="Mnemonic" type="input" @@ -38,19 +47,11 @@ export const Mnemonic = ({ }} /> - <Button - color="inherit" - disableElevation - size="large" - onClick={() => { - handleCopy(mnemonic); - }} - sx={{ - width: 250, - }} - endIcon={!copied ? <ContentCopySharp /> : <Check color="success" />} - > - Copy mnemonic - </Button> + {handleConfirmed && ( + <FormControlLabel + label="I saved my mnemonic" + control={<Checkbox checked={confirmed} onChange={(_, checked) => handleConfirmed(checked)} />} + /> + )} </Stack> ); diff --git a/nym-wallet/src/components/RewardsPlayground/inputsValidationSchema.ts b/nym-wallet/src/components/RewardsPlayground/inputsValidationSchema.ts index ef5d9ecc0d..2e44ec4cb5 100644 --- a/nym-wallet/src/components/RewardsPlayground/inputsValidationSchema.ts +++ b/nym-wallet/src/components/RewardsPlayground/inputsValidationSchema.ts @@ -35,7 +35,9 @@ export const inputValidationSchema = Yup.object().shape({ .test('Is valid operator cost value', (value, ctx) => { const stringValueToNumber = Math.round(Number(value)); - if (isGreaterThan(stringValueToNumber, -1) && isLessThan(stringValueToNumber, 101)) return true; - return ctx.createError({ message: 'Operator cost must be a valid number' }); + if (isLessThan(stringValueToNumber, 0)) + return ctx.createError({ message: 'Operator cost must be a valid number' }); + + return true; }), }); diff --git a/nym-wallet/src/pages/auth/components/password-strength.tsx b/nym-wallet/src/pages/auth/components/password-strength.tsx index 7e867f73fd..87ad9a3aa9 100644 --- a/nym-wallet/src/pages/auth/components/password-strength.tsx +++ b/nym-wallet/src/pages/auth/components/password-strength.tsx @@ -1,52 +1,61 @@ /* eslint-disable no-nested-ternary */ -import React, { useEffect, useState } from 'react'; +import React from 'react'; +import zxcvbn, { ZXCVBNScore } from 'zxcvbn'; import { LockOutlined } from '@mui/icons-material'; import { LinearProgress, Stack, Typography, Box } from '@mui/material'; -type TStrength = 'weak' | 'medium' | 'strong' | 'init'; - -const strong = /^(?=.*[a-z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})/; -const medium = /^(((?=.*[a-z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[0-9])))(?=.{6,})/; - const colorMap = { - init: 'inherit' as 'inherit', - weak: 'error' as 'error', - medium: 'warning' as 'warning', - strong: 'success' as 'success', + 4: 'success' as 'success', + 3: 'success' as 'success', + 2: 'warning' as 'warning', + 1: 'error' as 'error', + 0: 'error' as 'error', }; -const getText = (strength: TStrength) => { - switch (strength) { - case 'strong': +const getText = (score: ZXCVBNScore) => { + switch (score) { + case 4: + return 'Very strong password'; + case 3: return 'Strong password'; - case 'medium': - return 'Medium strength password'; - case 'weak': + case 2: + return 'Average password'; + case 1: return 'Weak password'; + case 0: + return 'Very weak password'; default: - return 'Password strength'; + return ''; } }; -const getTextColor = (strength: TStrength) => { - switch (strength) { - case 'strong': +const getColor = (score: ZXCVBNScore) => { + switch (score) { + case 4: return 'success.main'; - case 'medium': + case 3: + return 'success.main'; + case 2: return 'warning.main'; - case 'weak': + case 1: + return 'error.main'; + case 0: return 'error.main'; default: return 'grey.500'; } }; -const getPasswordStrength = (strength: TStrength) => { - switch (strength) { - case 'strong': +const getPasswordStrength = (score: ZXCVBNScore) => { + switch (score) { + case 4: return 100; - case 'medium': + case 3: + return 75; + case 2: return 50; + case 1: + return 25; default: return 0; } @@ -54,47 +63,32 @@ const getPasswordStrength = (strength: TStrength) => { export const PasswordStrength = ({ password, - onChange, + withWarnings, + handleIsSafePassword, }: { password: string; - onChange: (isStrong: boolean) => void; + withWarnings?: boolean; + handleIsSafePassword: (isSafe: boolean) => void; }) => { - const [strength, setStrength] = useState<TStrength>('init'); + const result = zxcvbn(password); - useEffect(() => { - if (password.length === 0) { - setStrength('init'); - return; - } + handleIsSafePassword(result.score > 1); - if (password.match(strong)) { - setStrength('strong'); - return; - } - - if (password.match(medium)) { - setStrength('medium'); - return; - } - setStrength('weak'); - }, [password]); - - useEffect(() => { - if (strength === 'strong') { - onChange(true); - } else { - onChange(false); - } - }, [strength]); + if (!password.length) return null; return ( <Stack spacing={0.5}> - <LinearProgress variant="determinate" color={colorMap[strength]} value={getPasswordStrength(strength)} /> - <Box display="flex" alignItems="center"> - <LockOutlined sx={{ fontSize: 15, color: getTextColor(strength) }} /> - <Typography variant="caption" sx={{ ml: 0.5, color: getTextColor(strength) }}> - {getText(strength)} - </Typography> + <LinearProgress variant="determinate" color={colorMap[result.score]} value={getPasswordStrength(result.score)} /> + <Box display="flex" alignItems="center" justifyContent="space-between"> + <Box display="flex" alignItems="center"> + <LockOutlined sx={{ fontSize: 15, color: getColor(result.score) }} /> + <Typography variant="caption" sx={{ ml: 0.5, color: getColor(result.score) }}> + {getText(result.score)} + </Typography> + </Box> + {withWarnings && result.feedback.warning && ( + <Typography variant="caption">{result.feedback.warning}</Typography> + )} </Box> </Stack> ); diff --git a/nym-wallet/src/pages/auth/components/passwordStrength.stories.tsx b/nym-wallet/src/pages/auth/components/passwordStrength.stories.tsx new file mode 100644 index 0000000000..3746b2015a --- /dev/null +++ b/nym-wallet/src/pages/auth/components/passwordStrength.stories.tsx @@ -0,0 +1,61 @@ +import * as React from 'react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Stack, TextField } from '@mui/material'; +import { PasswordStrength } from './password-strength'; + +export default { + title: 'Wallet / Password Strength', + component: PasswordStrength, +} as ComponentMeta<typeof PasswordStrength>; + +const Template: ComponentStory<typeof PasswordStrength> = ({ password, withWarnings, handleIsSafePassword }) => { + const [value, setValue] = React.useState(password); + return ( + <Stack alignContent="center"> + <TextField value={value} onChange={(e) => setValue(e.target.value)} sx={{ mb: 0.5 }} /> + {!!password.length && ( + <PasswordStrength handleIsSafePassword={handleIsSafePassword} withWarnings={withWarnings} password={password} /> + )} + </Stack> + ); +}; + +export const VeryStrong = Template.bind({}); +VeryStrong.args = { password: 'fedgklnrf34£', withWarnings: true, handleIsSafePassword: () => undefined }; + +export const Strong = Template.bind({}); +Strong.args = { password: '"56%abc123?@', withWarnings: true, handleIsSafePassword: () => undefined }; + +export const Average = Template.bind({}); +Average.args = { password: '"abc123?', withWarnings: true, handleIsSafePassword: () => undefined }; + +export const Weak = Template.bind({}); +Weak.args = { password: 'abc123?', withWarnings: true, handleIsSafePassword: () => undefined }; + +export const VeryWeak = Template.bind({}); +VeryWeak.args = { + password: 'abc123', + withWarnings: true, + handleIsSafePassword: () => undefined, +}; + +export const WithName = Template.bind({}); +WithName.args = { + password: 'fred', + withWarnings: true, + handleIsSafePassword: () => undefined, +}; + +export const WithSequence = Template.bind({}); +WithSequence.args = { + password: '121212', + withWarnings: true, + handleIsSafePassword: () => undefined, +}; + +export const Default = Template.bind({}); +Default.args = { + password: 'abc123', + withWarnings: true, + handleIsSafePassword: () => undefined, +}; diff --git a/nym-wallet/src/pages/auth/index.tsx b/nym-wallet/src/pages/auth/index.tsx deleted file mode 100644 index 598566db6f..0000000000 --- a/nym-wallet/src/pages/auth/index.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import { AuthProvider } from 'src/context'; -import { AuthRoutes } from 'src/routes/auth'; - -export const Auth = () => ( - <AuthProvider> - <AuthRoutes /> - </AuthProvider> -); diff --git a/nym-wallet/src/pages/auth/pages/connect-password.tsx b/nym-wallet/src/pages/auth/pages/connect-password.tsx index 133d0a27cb..476f0a9aca 100644 --- a/nym-wallet/src/pages/auth/pages/connect-password.tsx +++ b/nym-wallet/src/pages/auth/pages/connect-password.tsx @@ -9,9 +9,8 @@ import { Subtitle, Title, PasswordStrength } from '../components'; export const ConnectPassword = () => { const [confirmedPassword, setConfirmedPassword] = useState<string>(''); - const [isStrongPassword, setIsStrongPassword] = useState(false); const [isLoading, setIsLoading] = useState(false); - + const [isSafePassword, setIsSafePassword] = useState(false); const { mnemonic, password, setPassword, resetState } = useContext(AuthContext); const navigate = useNavigate(); @@ -49,7 +48,7 @@ export const ConnectPassword = () => { label="Password" autoFocus /> - <PasswordStrength password={password} onChange={(isStrong) => setIsStrongPassword(isStrong)} /> + <PasswordStrength password={password} handleIsSafePassword={setIsSafePassword} withWarnings /> </> <PasswordInput password={confirmedPassword} @@ -59,7 +58,7 @@ export const ConnectPassword = () => { <Button size="large" variant="contained" - disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading} + disabled={password !== confirmedPassword || password.length === 0 || isLoading || !isSafePassword} onClick={storePassword} > {isLoading ? <CircularProgress size={25} /> : 'Create password'} diff --git a/nym-wallet/src/pages/auth/pages/create-mnemonic.tsx b/nym-wallet/src/pages/auth/pages/create-mnemonic.tsx index 2809d3b3b1..e3ab373d55 100644 --- a/nym-wallet/src/pages/auth/pages/create-mnemonic.tsx +++ b/nym-wallet/src/pages/auth/pages/create-mnemonic.tsx @@ -1,13 +1,13 @@ -import React, { useContext, useEffect } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Container, Button, Stack } from '@mui/material'; import { AuthContext } from 'src/context/auth'; -import { useClipboard } from 'use-clipboard-copy'; import { Mnemonic } from '../../../components'; export const CreateMnemonic = () => { const { mnemonic, mnemonicWords, generateMnemonic, resetState } = useContext(AuthContext); const navigate = useNavigate(); + const [confirmed, setConfirmed] = useState(false); useEffect(() => { if (mnemonicWords.length === 0) { @@ -15,12 +15,10 @@ export const CreateMnemonic = () => { } }, []); - const { copy, copied } = useClipboard({ copiedTimeout: 5000 }); return ( - <Container maxWidth="xs"> + <Container maxWidth="sm"> <Stack alignItems="center" spacing={3} maxWidth="xs"> - <Mnemonic mnemonic={mnemonic} handleCopy={copy} copied={copied} /> - + <Mnemonic mnemonic={mnemonic} handleConfirmed={setConfirmed} confirmed={confirmed} withTitle /> <Button variant="contained" color="primary" @@ -28,9 +26,9 @@ export const CreateMnemonic = () => { size="large" onClick={() => navigate('/verify-mnemonic')} sx={{ width: '100%', fontSize: 15 }} - disabled={!copied} + disabled={!confirmed} > - I saved my mnemonic + Continue </Button> <Button onClick={() => { diff --git a/nym-wallet/src/pages/auth/pages/create-password.tsx b/nym-wallet/src/pages/auth/pages/create-password.tsx index cf894f20c4..e071c6dcea 100644 --- a/nym-wallet/src/pages/auth/pages/create-password.tsx +++ b/nym-wallet/src/pages/auth/pages/create-password.tsx @@ -10,8 +10,8 @@ import { Subtitle, Title, PasswordStrength } from '../components'; export const CreatePassword = () => { const { password, setPassword, resetState, mnemonic } = useContext(AuthContext); const [confirmedPassword, setConfirmedPassword] = useState<string>(''); - const [isStrongPassword, setIsStrongPassword] = useState(false); const [isLoading, setIsLoading] = useState(false); + const [isSafePassword, setIsSafePassword] = useState(false); const navigate = useNavigate(); @@ -48,7 +48,7 @@ export const CreatePassword = () => { label="Password" autoFocus /> - <PasswordStrength password={password} onChange={(isStrong) => setIsStrongPassword(isStrong)} /> + <PasswordStrength password={password} handleIsSafePassword={setIsSafePassword} withWarnings /> </> <PasswordInput password={confirmedPassword} @@ -58,7 +58,7 @@ export const CreatePassword = () => { <Button size="large" variant="contained" - disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading} + disabled={password !== confirmedPassword || password.length === 0 || isLoading || !isSafePassword} onClick={storePassword} > Next diff --git a/nym-wallet/src/pages/bonding/Bonding.tsx b/nym-wallet/src/pages/bonding/Bonding.tsx index 1eae1d3924..957f603d0e 100644 --- a/nym-wallet/src/pages/bonding/Bonding.tsx +++ b/nym-wallet/src/pages/bonding/Bonding.tsx @@ -17,6 +17,7 @@ import { AppContext, urls } from 'src/context/main'; import { isGateway, isMixnode, TBondGatewayArgs, TBondMixNodeArgs, TBondMoreArgs } from 'src/types'; import { BondedGateway } from 'src/components/Bonding/BondedGateway'; import { RedeemRewardsModal } from 'src/components/Bonding/modals/RedeemRewardsModal'; +import { Console } from 'src/utils/console'; import { BondingContextProvider, useBondingContext } from '../../context'; import { getMixnodeStakeSaturation } from '../../requests'; @@ -104,7 +105,7 @@ const Bonding = () => { } return { isOverSaturated: false, saturationPercentage: undefined }; } catch (e) { - console.error('Error fetching the saturation, error:', e); + Console.error('Error fetching the saturation, error:', e); return { isOverSaturated: false, saturationPercentage: undefined }; } }; diff --git a/nym-wallet/src/pages/bonding/node-settings/apy-playground/index.tsx b/nym-wallet/src/pages/bonding/node-settings/apy-playground/index.tsx index efac9050cb..65edb35bc5 100644 --- a/nym-wallet/src/pages/bonding/node-settings/apy-playground/index.tsx +++ b/nym-wallet/src/pages/bonding/node-settings/apy-playground/index.tsx @@ -7,6 +7,7 @@ import { CalculateArgs, Inputs } from 'src/components/RewardsPlayground/Inputs'; import { TBondedMixnode } from 'src/context'; import { useSnackbar } from 'notistack'; import { LoadingModal } from 'src/components/Modals/LoadingModal'; +import { Console } from 'src/utils/console'; import { computeEstimate, computeStakeSaturation, handleCalculatePeriodRewards } from './utils'; export type DefaultInputValues = { @@ -99,7 +100,7 @@ export const ApyPlayground = ({ bondedNode }: { bondedNode: TBondedMixnode }) => setStakeSaturation(computedStakeSaturation); setResults(estimationResult); } catch (e) { - console.log(e); + Console.log(e); } }; diff --git a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/ParametersSettings.tsx b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/ParametersSettings.tsx index a4e2bac152..0bff6c3ea3 100644 --- a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/ParametersSettings.tsx +++ b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/ParametersSettings.tsx @@ -56,7 +56,7 @@ export const ParametersSettings = ({ bondedNode }: { bondedNode: TBondedMixnode const { nextInterval } = await getIntervalAsDate(); setIntervalTime(nextInterval); } catch { - console.log('cant retrieve next interval'); + Console.log('cant retrieve next interval'); } }; diff --git a/nym-wallet/src/pages/index.ts b/nym-wallet/src/pages/index.ts index c2944d771c..21d21cf7b5 100644 --- a/nym-wallet/src/pages/index.ts +++ b/nym-wallet/src/pages/index.ts @@ -1,4 +1,3 @@ -export * from './auth'; export * from './Admin'; export * from './balance'; export * from './bonding'; diff --git a/nym-wallet/src/requests/queries.ts b/nym-wallet/src/requests/queries.ts index e80fd313fa..be74041f33 100644 --- a/nym-wallet/src/requests/queries.ts +++ b/nym-wallet/src/requests/queries.ts @@ -59,9 +59,5 @@ export const computeMixnodeRewardEstimation = async (args: { totalDelegation: number; profitMarginPercent: string; intervalOperatingCost: { denom: 'unym'; amount: string }; -}) => { - console.log(args); - - return invokeWrapper<RewardEstimationResponse>('compute_mixnode_reward_estimation', args); -}; +}) => invokeWrapper<RewardEstimationResponse>('compute_mixnode_reward_estimation', args); export const getMixnodeUptime = async (mixId: number) => invokeWrapper<number>('get_mixnode_uptime', { mixId }); diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index 26239e66c6..a28693c46f 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-network-requester" -version = "1.1.8" +version = "1.1.9" authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"] edition = "2021" rust-version = "1.65" diff --git a/service-providers/network-statistics/Cargo.toml b/service-providers/network-statistics/Cargo.toml index accdccc977..18c482c3c0 100644 --- a/service-providers/network-statistics/Cargo.toml +++ b/service-providers/network-statistics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-network-statistics" -version = "1.1.8" +version = "1.1.9" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/nym-cli/Cargo.toml b/tools/nym-cli/Cargo.toml index 7680ea44fe..ef0c22404b 100644 --- a/tools/nym-cli/Cargo.toml +++ b/tools/nym-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-cli" -version = "1.1.8" +version = "1.1.9" authors.workspace = true edition = "2021" diff --git a/ts-packages/react-components/src/components/mixnodes/IdentityKeyFormField.tsx b/ts-packages/react-components/src/components/mixnodes/IdentityKeyFormField.tsx index ec721408bf..4417bbffe5 100644 --- a/ts-packages/react-components/src/components/mixnodes/IdentityKeyFormField.tsx +++ b/ts-packages/react-components/src/components/mixnodes/IdentityKeyFormField.tsx @@ -19,7 +19,9 @@ export const IdentityKeyFormField: FCWithChildren<{ onValidate?: (isValid: boolean, error?: string) => void; textFieldProps?: TextFieldProps; errorText?: string; + size?: 'small' | 'medium'; sx?: SxProps; + disabled?: boolean; }> = ({ required, fullWidth, @@ -33,6 +35,8 @@ export const IdentityKeyFormField: FCWithChildren<{ onValidate, textFieldProps, showTickOnValid = true, + size, + disabled, }) => { const [value, setValue] = React.useState<string | undefined>(initialValue); const [validationError, setValidationError] = React.useState<string | undefined>(); @@ -100,6 +104,8 @@ export const IdentityKeyFormField: FCWithChildren<{ defaultValue={initialValue} onChange={handleChange} InputLabelProps={{ shrink: true }} + size={size} + disabled={disabled} /> ); }; diff --git a/yarn.lock b/yarn.lock index 4780ea8bd3..72e807cd97 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5338,6 +5338,11 @@ dependencies: "@types/yargs-parser" "*" +"@types/zxcvbn@^4.4.1": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@types/zxcvbn/-/zxcvbn-4.4.1.tgz#46e42cbdcee681b22181478feaf4af2bc4c1abd2" + integrity sha512-3NoqvZC2W5gAC5DZbTpCeJ251vGQmgcWIHQJGq2J240HY6ErQ9aWKkwfoKJlHLx+A83WPNTZ9+3cd2ILxbvr1w== + "@typescript-eslint/eslint-plugin@^5.13.0", "@typescript-eslint/eslint-plugin@^5.7.0": version "5.49.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.49.0.tgz#d0b4556f0792194bf0c2fb297897efa321492389" @@ -19683,3 +19688,8 @@ zwitch@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== + +zxcvbn@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/zxcvbn/-/zxcvbn-4.4.2.tgz#28ec17cf09743edcab056ddd8b1b06262cc73c30" + integrity sha512-Bq0B+ixT/DMyG8kgX2xWcI5jUvCwqrMxSFam7m0lAf78nf04hv6lNCsyLYdyYTrCVMqNDY/206K7eExYCeSyUQ==