Browse Source

Toolbox verify func. (#1749)

Jaco Greeff 5 years ago
parent
commit
64aa46d299
1 changed files with 113 additions and 179 deletions
  1. 113 179
      packages/app-toolbox/src/Verify.tsx

+ 113 - 179
packages/app-toolbox/src/Verify.tsx

@@ -5,7 +5,7 @@
 import { I18nProps as Props } from '@polkadot/react-components/types';
 import { KeypairType } from '@polkadot/util-crypto/types';
 
-import React from 'react';
+import React, { useEffect, useState } from 'react';
 import { Dropdown, Icon, Input, InputAddress, Static } from '@polkadot/react-components';
 import keyring from '@polkadot/ui-keyring';
 import uiSettings from '@polkadot/ui-settings';
@@ -17,211 +17,145 @@ import translate from './translate';
 
 type CryptoTypes = KeypairType | 'unknown';
 
-interface CryptoOption {
-  text: string;
-  value: string;
-}
-
-interface State {
-  currentPublicKey: Uint8Array | null;
-  cryptoOptions: CryptoOption[];
-  cryptoType: CryptoTypes;
-  defaultPublicKey?: Uint8Array;
-  data: string;
-  isHexData: boolean;
-  isValidAddress: boolean;
-  isValidSignature: boolean;
-  isValid: boolean;
-  signature: string;
-}
-
 const AlignedIcon = styled(Icon)`
   &&&::before {
     position: relative;
     left: 0.88rem;
-    top: 1rem; 
+    top: 1rem;
     width: 32px;
     height: 32px;
     font-size: 32px;
     background: white !important;
     border-radius: 50%;
   }
-  
+
   &&&.big.icon {
     font-size: 32px;
   }
 `;
 
-class Verify extends React.PureComponent<Props, State> {
-  public state: State;
-
-  public constructor (props: Props) {
-    super(props);
-
-    const { t } = this.props;
-    const pairs = keyring.getPairs();
-    const currentPair = pairs[0];
-    const currentPublicKey = currentPair
-      ? currentPair.publicKey
-      : null;
-
-    this.state = {
-      cryptoOptions: [{ value: 'unknown', text: t('Crypto not detected') }].concat(uiSettings.availableCryptos as any[]),
-      cryptoType: 'unknown',
-      currentPublicKey,
-      defaultPublicKey: currentPublicKey || undefined,
-      data: '',
-      isHexData: false,
-      isValidAddress: !!currentPair,
-      isValidSignature: false,
-      isValid: false,
-      signature: ''
-    };
-  }
-
-  public render (): React.ReactNode {
-    const { t } = this.props;
-    const { cryptoOptions, cryptoType, data, defaultPublicKey, isHexData, isValid, isValidAddress, isValidSignature, signature } = this.state;
-
-    return (
-      <div className='toolbox--Verify'>
-        <div className='ui--row'>
-          <InputAddress
-            className='full'
-            defaultValue={defaultPublicKey}
-            help={t('The account that signed the input')}
-            isError={!isValidAddress}
-            isInput
-            label={t('verify using address')}
-            onChange={this.onChangeAddress}
-          />
-        </div>
-        <div className='ui--row'>
-          <Input
-            autoFocus
-            className='full'
-            help={t('The data that was signed. This is used in combination with the signature for the verification. It can either be hex or a string.')}
-            label={t('using the following data')}
-            onChange={this.onChangeData}
-            value={data}
-          />
-        </div>
-        <div className='ui--row'>
-          <div className="ui--AlignedIconContainer" style={{ position: 'absolute', zIndex: 1 }}>
-            <AlignedIcon
-              color={isValid ? 'green' : (isValidSignature ? 'red' : undefined)}
-              name={isValid ? 'check circle' : (isValidSignature ? 'exclamation circle' : 'help circle')}
-              size="big"
-            />
-          </div>
-          <Input
-            className='full'
-            isError={!isValidSignature}
-            help={t('The signature as by the account being checked, supplied as a hex-formatted string.')}
-            label={t('the supplied signature')}
-            onChange={this.onChangeSignature}
-            value={signature}
-          />
-        </div>
-        <div className='ui--row'>
-          <Dropdown
-            defaultValue={cryptoType}
-            help={t('Cryptography used to create this signature. It is auto-detected on valid signatures.')}
-            isDisabled
-            label={t('signature crypto type')}
-            options={cryptoOptions}
-          />
-          <Static
-            className='medium'
-            help={t('Detection on the input string to determine if it is hex or non-hex.')}
-            label={t('hex input data')}
-            value={
-              isHexData
-                ? t('Yes')
-                : t('No')
-            }
-          />
-        </div>
-      </div>
-    );
-  }
-
-  private nextState (newState: Partial<State>): void {
-    this.setState(
-      (prevState: State): Pick<State, never> => {
-        const { isHexData = prevState.isHexData, isValidAddress = prevState.isValidAddress, isValidSignature = prevState.isValidSignature, currentPublicKey = prevState.currentPublicKey, data = prevState.data, signature = prevState.signature } = newState;
-        let cryptoType: CryptoTypes = 'unknown';
-        let isValid = isValidAddress && isValidSignature;
-
-        // We cannot just use the keyring verify since it may be an address. So here we first check
-        // for ed25519, if not valid, we try against sr25519 - if neither are valid, well, we have
-        // not been able to validate the signature
-        if (isValid && currentPublicKey) {
-          let isValidSr = false;
-          let isValidEd = false;
-
-          try {
-            isValidEd = naclVerify(data, signature, currentPublicKey);
-          } catch (error) {
-            // do nothing, already set to false
-          }
+function Verify ({ t }: Props): React.ReactElement<Props> {
+  const [{ cryptoType, isValid }, setValidity] = useState<{ cryptoType: CryptoTypes; isValid: boolean }>({ cryptoType: 'unknown', isValid: false });
+  const [{ data, isHexData }, setData] = useState<{ data: string; isHexData: boolean }>({ data: '', isHexData: false });
+  const [{ publicKey, isValidPk }, setPublicKey] = useState<{ publicKey: Uint8Array | null; isValidPk: boolean }>({ publicKey: null, isValidPk: false });
+  const [{ signature, isValidSignature }, setSignature] = useState<{ signature: string; isValidSignature: boolean }>({ signature: '', isValidSignature: false });
+  const [cryptoOptions] = useState([{ value: 'unknown', text: t('Crypto not detected') }].concat(uiSettings.availableCryptos as any[]));
+
+  useEffect((): void => {
+    let cryptoType: CryptoTypes = 'unknown';
+    let isValid = isValidPk && isValidSignature;
+
+    // We cannot just use the keyring verify since it may be an address. So here we first check
+    // for ed25519, if not valid, we try against sr25519 - if neither are valid, well, we have
+    // not been able to validate the signature
+    if (isValid && publicKey) {
+      let isValidSr = false;
+      let isValidEd = false;
+
+      try {
+        isValidEd = naclVerify(data, signature, publicKey);
+      } catch (error) {
+        // do nothing, already set to false
+      }
 
-          if (isValidEd) {
-            cryptoType = 'ed25519';
-          } else {
-            try {
-              isValidSr = schnorrkelVerify(data, signature, currentPublicKey);
-            } catch (error) {
-              // do nothing, already set to false
-            }
-
-            if (isValidSr) {
-              cryptoType = 'sr25519';
-            } else {
-              isValid = false;
-            }
-          }
+      if (isValidEd) {
+        cryptoType = 'ed25519';
+      } else {
+        try {
+          isValidSr = schnorrkelVerify(data, signature, publicKey);
+        } catch (error) {
+          // do nothing, already set to false
         }
 
-        return {
-          cryptoType,
-          isHexData,
-          isValid,
-          isValidAddress,
-          isValidSignature,
-          currentPublicKey,
-          data,
-          signature
-        };
+        if (isValidSr) {
+          cryptoType = 'sr25519';
+        } else {
+          isValid = false;
+        }
       }
-    );
-  }
-
-  private onChangeData = (data: string): void => {
-    const isHexData = isHex(data);
-
-    this.nextState({ data, isHexData });
-  }
-
-  private onChangeSignature = (signature: string): void => {
-    const isValidSignature = isHex(signature) && signature.length === 130;
+    }
 
-    this.nextState({ signature, isValidSignature });
-  }
+    setValidity({ cryptoType, isValid });
+  }, [data, isValidPk, isValidSignature, publicKey, signature]);
 
-  private onChangeAddress = (accountId: string | null): void => {
-    let currentPublicKey;
+  const _onChangeAddress = (accountId: string | null): void => {
+    let publicKey: Uint8Array | null = null;
 
     try {
-      currentPublicKey = keyring.decodeAddress(accountId || '');
+      publicKey = keyring.decodeAddress(accountId || '');
     } catch (err) {
       console.error(err);
     }
 
-    const isValidAddress = currentPublicKey && currentPublicKey.length === 32;
-
-    this.nextState({ currentPublicKey, isValidAddress });
-  }
+    setPublicKey({ publicKey, isValidPk: !!publicKey && publicKey.length === 32 });
+  };
+
+  const _onChangeData = (data: string): void =>
+    setData({ data, isHexData: isHex(data) });
+
+  const _onChangeSignature = (signature: string): void =>
+    setSignature({ signature, isValidSignature: isHex(signature) && signature.length === 130 });
+
+  return (
+    <div className='toolbox--Verify'>
+      <div className='ui--row'>
+        <InputAddress
+          className='full'
+          help={t('The account that signed the input')}
+          isError={!isValidPk}
+          isInput
+          label={t('verify using address')}
+          onChange={_onChangeAddress}
+        />
+      </div>
+      <div className='ui--row'>
+        <Input
+          autoFocus
+          className='full'
+          help={t('The data that was signed. This is used in combination with the signature for the verification. It can either be hex or a string.')}
+          label={t('using the following data')}
+          onChange={_onChangeData}
+          value={data}
+        />
+      </div>
+      <div className='ui--row'>
+        <div className="ui--AlignedIconContainer" style={{ position: 'absolute', zIndex: 1 }}>
+          <AlignedIcon
+            color={isValid ? 'green' : (isValidSignature ? 'red' : undefined)}
+            name={isValid ? 'check circle' : (isValidSignature ? 'exclamation circle' : 'help circle')}
+            size="big"
+          />
+        </div>
+        <Input
+          className='full'
+          isError={!isValidSignature}
+          help={t('The signature as by the account being checked, supplied as a hex-formatted string.')}
+          label={t('the supplied signature')}
+          onChange={_onChangeSignature}
+          value={signature}
+        />
+      </div>
+      <div className='ui--row'>
+        <Dropdown
+          defaultValue={cryptoType}
+          help={t('Cryptography used to create this signature. It is auto-detected on valid signatures.')}
+          isDisabled
+          label={t('signature crypto type')}
+          options={cryptoOptions}
+        />
+        <Static
+          className='medium'
+          help={t('Detection on the input string to determine if it is hex or non-hex.')}
+          label={t('hex input data')}
+          value={
+            isHexData
+              ? t('Yes')
+              : t('No')
+          }
+        />
+      </div>
+    </div>
+  );
 }
 
 export default translate(Verify);