|
@@ -1,140 +1,134 @@
|
|
|
-import {RouteComponentProps} from 'react-router';
|
|
|
-
|
|
|
import ExternalLink from 'sentry/components/links/externalLink';
|
|
|
+import LoadingError from 'sentry/components/loadingError';
|
|
|
+import LoadingIndicator from 'sentry/components/loadingIndicator';
|
|
|
import Panel from 'sentry/components/panels/panel';
|
|
|
import PanelBody from 'sentry/components/panels/panelBody';
|
|
|
import PanelHeader from 'sentry/components/panels/panelHeader';
|
|
|
import PreviewFeature from 'sentry/components/previewFeature';
|
|
|
+import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
|
|
|
import {t, tct} from 'sentry/locale';
|
|
|
-import {Organization, ProjectKey} from 'sentry/types';
|
|
|
+import {ProjectKey} from 'sentry/types';
|
|
|
+import {useApiQuery} from 'sentry/utils/queryClient';
|
|
|
import routeTitleGen from 'sentry/utils/routeTitle';
|
|
|
-import withOrganization from 'sentry/utils/withOrganization';
|
|
|
-import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView';
|
|
|
+import useOrganization from 'sentry/utils/useOrganization';
|
|
|
+import {useParams} from 'sentry/utils/useParams';
|
|
|
import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
|
|
|
import ReportUri, {
|
|
|
getSecurityDsn,
|
|
|
} from 'sentry/views/settings/projectSecurityHeaders/reportUri';
|
|
|
|
|
|
-type Props = RouteComponentProps<{projectId: string}, {}> & {
|
|
|
- organization: Organization;
|
|
|
-};
|
|
|
-
|
|
|
-type State = {
|
|
|
- keyList: null | ProjectKey[];
|
|
|
-} & DeprecatedAsyncView['state'];
|
|
|
-
|
|
|
-class ProjectHpkpReports extends DeprecatedAsyncView<Props, State> {
|
|
|
- getEndpoints(): ReturnType<DeprecatedAsyncView['getEndpoints']> {
|
|
|
- const {organization} = this.props;
|
|
|
- const {projectId} = this.props.params;
|
|
|
- return [['keyList', `/projects/${organization.slug}/${projectId}/keys/`]];
|
|
|
- }
|
|
|
+function getInstructions(keyList: ProjectKey[]) {
|
|
|
+ return (
|
|
|
+ 'def middleware(request, response):\n' +
|
|
|
+ " response['Public-Key-Pins'] = \\\n" +
|
|
|
+ ' \'pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs="; \' \\\n' +
|
|
|
+ ' \'pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="; \' \\\n' +
|
|
|
+ " 'max-age=5184000; includeSubDomains; ' \\\n" +
|
|
|
+ ` \'report-uri="${getSecurityDsn(keyList)}"\' \n` +
|
|
|
+ ' return response\n'
|
|
|
+ );
|
|
|
+}
|
|
|
|
|
|
- getTitle() {
|
|
|
- const {projectId} = this.props.params;
|
|
|
- return routeTitleGen(t('HTTP Public Key Pinning (HPKP)'), projectId, false);
|
|
|
- }
|
|
|
+function getReportOnlyInstructions(keyList: ProjectKey[]) {
|
|
|
+ return (
|
|
|
+ 'def middleware(request, response):\n' +
|
|
|
+ " response['Public-Key-Pins-Report-Only'] = \\\n" +
|
|
|
+ ' \'pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs="; \' \\\n' +
|
|
|
+ ' \'pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="; \' \\\n' +
|
|
|
+ " 'max-age=5184000; includeSubDomains; ' \\\n" +
|
|
|
+ ` \'report-uri="${getSecurityDsn(keyList)}"\' \n` +
|
|
|
+ ' return response\n'
|
|
|
+ );
|
|
|
+}
|
|
|
|
|
|
- getInstructions(keyList: ProjectKey[]) {
|
|
|
- return (
|
|
|
- 'def middleware(request, response):\n' +
|
|
|
- " response['Public-Key-Pins'] = \\\n" +
|
|
|
- ' \'pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs="; \' \\\n' +
|
|
|
- ' \'pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="; \' \\\n' +
|
|
|
- " 'max-age=5184000; includeSubDomains; ' \\\n" +
|
|
|
- ` \'report-uri="${getSecurityDsn(keyList)}"\' \n` +
|
|
|
- ' return response\n'
|
|
|
- );
|
|
|
+function ProjectHpkpReports() {
|
|
|
+ const organization = useOrganization();
|
|
|
+ const {projectId} = useParams();
|
|
|
+
|
|
|
+ const {
|
|
|
+ data: keyList,
|
|
|
+ isLoading,
|
|
|
+ isError,
|
|
|
+ refetch,
|
|
|
+ } = useApiQuery<ProjectKey[]>([`/projects/${organization.slug}/${projectId}/keys/`], {
|
|
|
+ staleTime: 0,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (isLoading) {
|
|
|
+ return <LoadingIndicator />;
|
|
|
}
|
|
|
|
|
|
- getReportOnlyInstructions(keyList: ProjectKey[]) {
|
|
|
- return (
|
|
|
- 'def middleware(request, response):\n' +
|
|
|
- " response['Public-Key-Pins-Report-Only'] = \\\n" +
|
|
|
- ' \'pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs="; \' \\\n' +
|
|
|
- ' \'pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="; \' \\\n' +
|
|
|
- " 'max-age=5184000; includeSubDomains; ' \\\n" +
|
|
|
- ` \'report-uri="${getSecurityDsn(keyList)}"\' \n` +
|
|
|
- ' return response\n'
|
|
|
- );
|
|
|
+ if (isError) {
|
|
|
+ return <LoadingError onRetry={refetch} />;
|
|
|
}
|
|
|
|
|
|
- renderBody() {
|
|
|
- const {organization, params} = this.props;
|
|
|
- const {keyList} = this.state;
|
|
|
- if (!keyList) {
|
|
|
- return null;
|
|
|
- }
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <SentryDocumentTitle
|
|
|
+ title={routeTitleGen(t('HTTP Public Key Pinning (HPKP)'), projectId, false)}
|
|
|
+ />
|
|
|
+ <SettingsPageHeader title={t('HTTP Public Key Pinning')} />
|
|
|
|
|
|
- return (
|
|
|
- <div>
|
|
|
- <SettingsPageHeader title={t('HTTP Public Key Pinning')} />
|
|
|
+ <PreviewFeature />
|
|
|
|
|
|
- <PreviewFeature />
|
|
|
+ <ReportUri keyList={keyList} orgId={organization.slug} projectId={projectId} />
|
|
|
|
|
|
- <ReportUri
|
|
|
- keyList={keyList}
|
|
|
- orgId={organization.slug}
|
|
|
- projectId={params.projectId}
|
|
|
- />
|
|
|
+ <Panel>
|
|
|
+ <PanelHeader>{t('About')}</PanelHeader>
|
|
|
|
|
|
- <Panel>
|
|
|
- <PanelHeader>{t('About')}</PanelHeader>
|
|
|
-
|
|
|
- <PanelBody withPadding>
|
|
|
- <p>
|
|
|
- {tct(
|
|
|
- `[link:HTTP Public Key Pinning]
|
|
|
+ <PanelBody withPadding>
|
|
|
+ <p>
|
|
|
+ {tct(
|
|
|
+ `[link:HTTP Public Key Pinning]
|
|
|
(HPKP) is a security feature that tells a web client to associate a specific
|
|
|
cryptographic public key with a certain web server to decrease the risk of MITM
|
|
|
attacks with forged certificates. It's enforced by browser vendors, and Sentry
|
|
|
supports capturing violations using the standard reporting hooks.`,
|
|
|
- {
|
|
|
- link: (
|
|
|
- <ExternalLink href="https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning" />
|
|
|
- ),
|
|
|
- }
|
|
|
- )}
|
|
|
- </p>
|
|
|
-
|
|
|
- <p>
|
|
|
- {t(
|
|
|
- `To configure HPKP reports
|
|
|
+ {
|
|
|
+ link: (
|
|
|
+ <ExternalLink href="https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning" />
|
|
|
+ ),
|
|
|
+ }
|
|
|
+ )}
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <p>
|
|
|
+ {t(
|
|
|
+ `To configure HPKP reports
|
|
|
in Sentry, you'll need to send a header from your server describing your
|
|
|
policy, as well specifying the authenticated Sentry endpoint.`
|
|
|
- )}
|
|
|
- </p>
|
|
|
-
|
|
|
- <p>
|
|
|
- {t(
|
|
|
- 'For example, in Python you might achieve this via a simple web middleware'
|
|
|
- )}
|
|
|
- </p>
|
|
|
- <pre>{this.getInstructions(keyList)}</pre>
|
|
|
-
|
|
|
- <p>
|
|
|
- {t(`Alternatively you can setup HPKP reports to simply send reports rather than
|
|
|
+ )}
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <p>
|
|
|
+ {t(
|
|
|
+ 'For example, in Python you might achieve this via a simple web middleware'
|
|
|
+ )}
|
|
|
+ </p>
|
|
|
+ <pre>{getInstructions(keyList)}</pre>
|
|
|
+
|
|
|
+ <p>
|
|
|
+ {t(`Alternatively you can setup HPKP reports to simply send reports rather than
|
|
|
actually enforcing the policy`)}
|
|
|
- </p>
|
|
|
- <pre>{this.getReportOnlyInstructions(keyList)}</pre>
|
|
|
+ </p>
|
|
|
+ <pre>{getReportOnlyInstructions(keyList)}</pre>
|
|
|
|
|
|
- <p>
|
|
|
- {tct(
|
|
|
- `We recommend setting this up to only run on a percentage of requests, as
|
|
|
+ <p>
|
|
|
+ {tct(
|
|
|
+ `We recommend setting this up to only run on a percentage of requests, as
|
|
|
otherwise you may find that you've quickly exhausted your quota. For more
|
|
|
information, take a look at [link:the documentation on MDN].`,
|
|
|
- {
|
|
|
- link: (
|
|
|
- <ExternalLink href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning" />
|
|
|
- ),
|
|
|
- }
|
|
|
- )}
|
|
|
- </p>
|
|
|
- </PanelBody>
|
|
|
- </Panel>
|
|
|
- </div>
|
|
|
- );
|
|
|
- }
|
|
|
+ {
|
|
|
+ link: (
|
|
|
+ <ExternalLink href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning" />
|
|
|
+ ),
|
|
|
+ }
|
|
|
+ )}
|
|
|
+ </p>
|
|
|
+ </PanelBody>
|
|
|
+ </Panel>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
-export default withOrganization(ProjectHpkpReports);
|
|
|
+export default ProjectHpkpReports;
|