github.com/argoproj/argo-cd@v1.8.7/ui/src/app/settings/components/gpgkeys-list/gpgkeys-list.tsx (about)

     1  import {DropDownMenu, FormField, NotificationType, SlidingPanel} from 'argo-ui';
     2  import * as PropTypes from 'prop-types';
     3  import * as React from 'react';
     4  import {Form, FormApi, TextArea} from 'react-form';
     5  import {RouteComponentProps} from 'react-router';
     6  
     7  import {DataLoader, EmptyState, ErrorNotification, Page} from '../../../shared/components';
     8  import {AppContext} from '../../../shared/context';
     9  import * as models from '../../../shared/models';
    10  import {services} from '../../../shared/services';
    11  
    12  require('./gpgkeys-list.scss');
    13  
    14  interface NewGnuPGPublicKeyParams {
    15      keyData: string;
    16  }
    17  
    18  export class GpgKeysList extends React.Component<RouteComponentProps<any>> {
    19      public static contextTypes = {
    20          router: PropTypes.object,
    21          apis: PropTypes.object,
    22          history: PropTypes.object
    23      };
    24  
    25      private formApi: FormApi;
    26      private loader: DataLoader;
    27  
    28      public render() {
    29          return (
    30              <Page
    31                  title='GnuPG public keys'
    32                  toolbar={{
    33                      breadcrumbs: [{title: 'Settings', path: '/settings'}, {title: 'GnuPG public keys'}],
    34                      actionMenu: {
    35                          className: 'fa fa-plus',
    36                          items: [
    37                              {
    38                                  title: 'Add GnuPG key',
    39                                  action: () => (this.showAddGnuPGKey = true)
    40                              }
    41                          ]
    42                      }
    43                  }}>
    44                  <div className='gpgkeys-list'>
    45                      <div className='argo-container'>
    46                          <DataLoader load={() => services.gpgkeys.list()} ref={loader => (this.loader = loader)}>
    47                              {(gpgkeys: models.GnuPGPublicKey[]) =>
    48                                  (gpgkeys.length > 0 && (
    49                                      <div className='argo-table-list'>
    50                                          <div className='argo-table-list__head'>
    51                                              <div className='row'>
    52                                                  <div className='columns small-3'>KEY ID</div>
    53                                                  <div className='columns small-3'>KEY TYPE</div>
    54                                                  <div className='columns small-6'>IDENTITY</div>
    55                                              </div>
    56                                          </div>
    57                                          {gpgkeys.map(gpgkey => (
    58                                              <div className='argo-table-list__row' key={gpgkey.keyID}>
    59                                                  <div className='row'>
    60                                                      <div className='columns small-3'>
    61                                                          <i className='fa fa-key' /> {gpgkey.keyID}
    62                                                      </div>
    63                                                      <div className='columns small-3'>{gpgkey.subType.toUpperCase()}</div>
    64                                                      <div className='columns small-6'>
    65                                                          {gpgkey.owner}
    66                                                          <DropDownMenu
    67                                                              anchor={() => (
    68                                                                  <button className='argo-button argo-button--light argo-button--lg argo-button--short'>
    69                                                                      <i className='fa fa-ellipsis-v' />
    70                                                                  </button>
    71                                                              )}
    72                                                              items={[
    73                                                                  {
    74                                                                      title: 'Remove',
    75                                                                      action: () => this.removeKey(gpgkey.keyID)
    76                                                                  }
    77                                                              ]}
    78                                                          />
    79                                                      </div>
    80                                                  </div>
    81                                              </div>
    82                                          ))}
    83                                      </div>
    84                                  )) || (
    85                                      <EmptyState icon='fa fa-key'>
    86                                          <h4>No GnuPG public keys currently configured</h4>
    87                                          <h5>You can add GnuPG public keys below..</h5>
    88                                          <button className='argo-button argo-button--base' onClick={() => (this.showAddGnuPGKey = true)}>
    89                                              Add GnuPG public key
    90                                          </button>
    91                                      </EmptyState>
    92                                  )
    93                              }
    94                          </DataLoader>
    95                      </div>
    96                  </div>
    97                  <SlidingPanel
    98                      isShown={this.showAddGnuPGKey}
    99                      onClose={() => (this.showAddGnuPGKey = false)}
   100                      header={
   101                          <div>
   102                              <button className='argo-button argo-button--base' onClick={() => this.formApi.submitForm(null)}>
   103                                  Create
   104                              </button>{' '}
   105                              <button onClick={() => (this.showAddGnuPGKey = false)} className='argo-button argo-button--base-o'>
   106                                  Cancel
   107                              </button>
   108                          </div>
   109                      }>
   110                      <h4>Add GnuPG public key</h4>
   111                      <Form
   112                          onSubmit={params => this.addGnuPGPublicKey({keyData: params.keyData})}
   113                          getApi={api => (this.formApi = api)}
   114                          preSubmit={(params: NewGnuPGPublicKeyParams) => ({
   115                              keyData: params.keyData
   116                          })}
   117                          validateError={(params: NewGnuPGPublicKeyParams) => ({
   118                              keyData: !params.keyData && 'Key data is required'
   119                          })}>
   120                          {formApi => (
   121                              <form onSubmit={formApi.submitForm} role='form' className='gpgkeys-list width-control' encType='multipart/form-data'>
   122                                  <div className='argo-form-row'>
   123                                      <FormField formApi={formApi} label='GnuPG public key data (ASCII-armored)' field='keyData' component={TextArea} />
   124                                  </div>
   125                              </form>
   126                          )}
   127                      </Form>
   128                  </SlidingPanel>
   129              </Page>
   130          );
   131      }
   132  
   133      private clearForms() {
   134          this.formApi.resetAll();
   135      }
   136  
   137      private validateKeyInputfield(data: string): boolean {
   138          if (data == null || data === '') {
   139              return false;
   140          }
   141          const str = data.trim();
   142          const startNeedle = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n';
   143          const endNeedle = '\n-----END PGP PUBLIC KEY BLOCK-----';
   144  
   145          if (str.length < startNeedle.length + endNeedle.length) {
   146              return false;
   147          }
   148          if (!str.startsWith(startNeedle)) {
   149              return false;
   150          }
   151          if (!str.endsWith(endNeedle)) {
   152              return false;
   153          }
   154          return true;
   155      }
   156  
   157      private async addGnuPGPublicKey(params: NewGnuPGPublicKeyParams) {
   158          try {
   159              if (!this.validateKeyInputfield(params.keyData)) {
   160                  throw {
   161                      name: 'Invalid key exception',
   162                      message: 'Invalid GnuPG key data found - must be ASCII armored'
   163                  };
   164              }
   165              await services.gpgkeys.create({keyData: params.keyData});
   166              this.showAddGnuPGKey = false;
   167              this.loader.reload();
   168          } catch (e) {
   169              this.appContext.apis.notifications.show({
   170                  content: <ErrorNotification title='Unable to add GnuPG public key' e={e} />,
   171                  type: NotificationType.Error
   172              });
   173          }
   174      }
   175  
   176      private async removeKey(keyId: string) {
   177          const confirmed = await this.appContext.apis.popup.confirm('Remove GPG public key', 'Are you sure you want to remove GPG key with ID ' + keyId + '?');
   178          if (confirmed) {
   179              await services.gpgkeys.delete(keyId);
   180              this.loader.reload();
   181          }
   182      }
   183  
   184      private get showAddGnuPGKey() {
   185          return new URLSearchParams(this.props.location.search).get('addGnuPGPublicKey') === 'true';
   186      }
   187  
   188      private set showAddGnuPGKey(val: boolean) {
   189          this.clearForms();
   190          this.appContext.router.history.push(`${this.props.match.url}?addGnuPGPublicKey=${val}`);
   191      }
   192  
   193      private get appContext(): AppContext {
   194          return this.context as AppContext;
   195      }
   196  }