index.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import {RouteComponentProps} from 'react-router';
  2. import styled from '@emotion/styled';
  3. import {Button} from 'sentry/components/button';
  4. import {KeyValueTable, KeyValueTableRow} from 'sentry/components/keyValueTable';
  5. import Panel from 'sentry/components/panels/panel';
  6. import PanelBody from 'sentry/components/panels/panelBody';
  7. import PanelHeader from 'sentry/components/panels/panelHeader';
  8. import PanelItem from 'sentry/components/panels/panelItem';
  9. import {t, tct} from 'sentry/locale';
  10. import {Organization, ProjectKey} from 'sentry/types';
  11. import recreateRoute from 'sentry/utils/recreateRoute';
  12. import routeTitleGen from 'sentry/utils/routeTitle';
  13. import withOrganization from 'sentry/utils/withOrganization';
  14. import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView';
  15. import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
  16. import TextBlock from 'sentry/views/settings/components/text/textBlock';
  17. import ReportUri from 'sentry/views/settings/projectSecurityHeaders/reportUri';
  18. type Props = {
  19. organization: Organization;
  20. } & RouteComponentProps<{projectId: string}, {}>;
  21. type State = {
  22. keyList: null | ProjectKey[];
  23. } & DeprecatedAsyncView['state'];
  24. class ProjectSecurityHeaders extends DeprecatedAsyncView<Props, State> {
  25. getEndpoints(): ReturnType<DeprecatedAsyncView['getEndpoints']> {
  26. const {organization} = this.props;
  27. const {projectId} = this.props.params;
  28. return [['keyList', `/projects/${organization.slug}/${projectId}/keys/`]];
  29. }
  30. getTitle() {
  31. const {projectId} = this.props.params;
  32. return routeTitleGen(t('Security Headers'), projectId, false);
  33. }
  34. getReports() {
  35. return [
  36. {
  37. name: 'Content Security Policy (CSP)',
  38. url: recreateRoute('csp/', this.props),
  39. },
  40. {
  41. name: 'Certificate Transparency (Expect-CT)',
  42. url: recreateRoute('expect-ct/', this.props),
  43. },
  44. {
  45. name: 'HTTP Public Key Pinning (HPKP)',
  46. url: recreateRoute('hpkp/', this.props),
  47. },
  48. ];
  49. }
  50. renderBody() {
  51. const {organization, params} = this.props;
  52. const {keyList} = this.state;
  53. if (keyList === null) {
  54. return null;
  55. }
  56. return (
  57. <div>
  58. <SettingsPageHeader title={t('Security Header Reports')} />
  59. <ReportUri
  60. keyList={keyList}
  61. projectId={params.projectId}
  62. orgId={organization.slug}
  63. />
  64. <Panel>
  65. <PanelHeader>{t('Additional Configuration')}</PanelHeader>
  66. <PanelBody withPadding>
  67. <TextBlock style={{marginBottom: 20}}>
  68. {tct(
  69. 'In addition to the [key_param] parameter, you may also pass the following within the querystring for the report URI:',
  70. {
  71. key_param: <code>sentry_key</code>,
  72. }
  73. )}
  74. </TextBlock>
  75. <KeyValueTable>
  76. <KeyValueTableRow
  77. keyName="sentry_environment"
  78. value={t('The environment name (e.g. production).')}
  79. />
  80. <KeyValueTableRow
  81. keyName="sentry_release"
  82. value={t('The version of the application.')}
  83. />
  84. </KeyValueTable>
  85. </PanelBody>
  86. </Panel>
  87. <Panel>
  88. <PanelHeader>{t('Supported Formats')}</PanelHeader>
  89. <PanelBody>
  90. {this.getReports().map(({name, url}) => (
  91. <ReportItem key={url}>
  92. <HeaderName>{name}</HeaderName>
  93. <Button to={url} priority="primary">
  94. {t('Instructions')}
  95. </Button>
  96. </ReportItem>
  97. ))}
  98. </PanelBody>
  99. </Panel>
  100. </div>
  101. );
  102. }
  103. }
  104. export default withOrganization(ProjectSecurityHeaders);
  105. const ReportItem = styled(PanelItem)`
  106. align-items: center;
  107. justify-content: space-between;
  108. `;
  109. const HeaderName = styled('span')`
  110. font-size: 1.2em;
  111. `;