github.com/argoproj/argo-cd/v2@v2.10.9/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                                  iconClassName: 'fa fa-plus',
    40                                  action: () => (this.showAddGnuPGKey = true)
    41                              }
    42                          ]
    43                      }
    44                  }}>
    45                  <div className='gpgkeys-list'>
    46                      <div className='argo-container'>
    47                          <DataLoader load={() => services.gpgkeys.list()} ref={loader => (this.loader = loader)}>
    48                              {(gpgkeys: models.GnuPGPublicKey[]) =>
    49                                  (gpgkeys.length > 0 && (
    50                                      <div className='argo-table-list'>
    51                                          <div className='argo-table-list__head'>
    52                                              <div className='row'>
    53                                                  <div className='columns small-3'>KEY ID</div>
    54                                                  <div className='columns small-3'>KEY TYPE</div>
    55                                                  <div className='columns small-6'>IDENTITY</div>
    56                                              </div>
    57                                          </div>
    58                                          {gpgkeys.map(gpgkey => (
    59                                              <div className='argo-table-list__row' key={gpgkey.keyID}>
    60                                                  <div className='row'>
    61                                                      <div className='columns small-3'>
    62                                                          <i className='fa fa-key' /> {gpgkey.keyID}
    63                                                      </div>
    64                                                      <div className='columns small-3'>{gpgkey.subType.toUpperCase()}</div>
    65                                                      <div className='columns small-6'>
    66                                                          {gpgkey.owner}
    67                                                          <DropDownMenu
    68                                                              anchor={() => (
    69                                                                  <button className='argo-button argo-button--light argo-button--lg argo-button--short'>
    70                                                                      <i className='fa fa-ellipsis-v' />
    71                                                                  </button>
    72                                                              )}
    73                                                              items={[
    74                                                                  {
    75                                                                      title: 'Remove',
    76                                                                      action: () => this.removeKey(gpgkey.keyID)
    77                                                                  }
    78                                                              ]}
    79                                                          />
    80                                                      </div>
    81                                                  </div>
    82                                              </div>
    83                                          ))}
    84                                      </div>
    85                                  )) || (
    86                                      <EmptyState icon='fa fa-key'>
    87                                          <h4>No GnuPG public keys currently configured</h4>
    88                                          <h5>You can add GnuPG public keys below..</h5>
    89                                          <button className='argo-button argo-button--base' onClick={() => (this.showAddGnuPGKey = true)}>
    90                                              Add GnuPG public key
    91                                          </button>
    92                                      </EmptyState>
    93                                  )
    94                              }
    95                          </DataLoader>
    96                      </div>
    97                  </div>
    98                  <SlidingPanel
    99                      isShown={this.showAddGnuPGKey}
   100                      onClose={() => (this.showAddGnuPGKey = false)}
   101                      header={
   102                          <div>
   103                              <button className='argo-button argo-button--base' onClick={() => this.formApi.submitForm(null)}>
   104                                  Create
   105                              </button>{' '}
   106                              <button onClick={() => (this.showAddGnuPGKey = false)} className='argo-button argo-button--base-o'>
   107                                  Cancel
   108                              </button>
   109                          </div>
   110                      }>
   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 && 'GnuPG public 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='white-box'>
   123                                      <p>ADD GnuPG PUBLIC KEY</p>
   124                                      <div className='argo-form-row'>
   125                                          <FormField formApi={formApi} label='GnuPG public key data (ASCII-armored)' field='keyData' component={TextArea} />
   126                                      </div>
   127                                  </div>
   128                              </form>
   129                          )}
   130                      </Form>
   131                  </SlidingPanel>
   132              </Page>
   133          );
   134      }
   135  
   136      private clearForms() {
   137          this.formApi.resetAll();
   138      }
   139  
   140      private validateKeyInputfield(data: string): boolean {
   141          if (data == null || data === '') {
   142              return false;
   143          }
   144          const str = data.trim();
   145          const startNeedle = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n';
   146          const endNeedle = '\n-----END PGP PUBLIC KEY BLOCK-----';
   147  
   148          if (str.length < startNeedle.length + endNeedle.length) {
   149              return false;
   150          }
   151          if (!str.startsWith(startNeedle)) {
   152              return false;
   153          }
   154          if (!str.endsWith(endNeedle)) {
   155              return false;
   156          }
   157          return true;
   158      }
   159  
   160      private async addGnuPGPublicKey(params: NewGnuPGPublicKeyParams) {
   161          try {
   162              if (!this.validateKeyInputfield(params.keyData)) {
   163                  throw {
   164                      name: 'Invalid key exception',
   165                      message: 'Invalid GnuPG key data found - must be ASCII armored'
   166                  };
   167              }
   168              await services.gpgkeys.create({keyData: params.keyData});
   169              this.showAddGnuPGKey = false;
   170              this.loader.reload();
   171          } catch (e) {
   172              this.appContext.apis.notifications.show({
   173                  content: <ErrorNotification title='Unable to add GnuPG public key' e={e} />,
   174                  type: NotificationType.Error
   175              });
   176          }
   177      }
   178  
   179      private async removeKey(keyId: string) {
   180          const confirmed = await this.appContext.apis.popup.confirm('Remove GPG public key', 'Are you sure you want to remove GPG key with ID ' + keyId + '?');
   181          if (confirmed) {
   182              await services.gpgkeys.delete(keyId);
   183              this.loader.reload();
   184          }
   185      }
   186  
   187      private get showAddGnuPGKey() {
   188          return new URLSearchParams(this.props.location.search).get('addGnuPGPublicKey') === 'true';
   189      }
   190  
   191      private set showAddGnuPGKey(val: boolean) {
   192          this.clearForms();
   193          this.appContext.router.history.push(`${this.props.match.url}?addGnuPGPublicKey=${val}`);
   194      }
   195  
   196      private get appContext(): AppContext {
   197          return this.context as AppContext;
   198      }
   199  }