PluginProbe
CryptX / 4.2.1
CryptX v4.2.1
4.2.1 4.2.0 4.1.1 trunk 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.9 2.0 2.1 2.2 2.3 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 All 93 releases
cryptx / src / components / Secrets.js

Secrets.js in CryptX 4.2.1, at src/components/Secrets.js

134 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Replacing the two secrets CryptX keeps.
3 *
4 * Sits on the Advanced tab for the same reason the preview sits on Appearance:
5 * it is an action, not a setting, and it belongs where somebody would look for
6 * it rather than in a row of switches.
7 *
8 * The text carries the one thing that decides whether pressing it is safe, and
9 * it is not obvious: links already published go on working for ever, because
10 * the key travels inside them. Pictures do not -- their token is opened on the
11 * server -- so the replaced secret is kept for a while and the screen says
12 * until when.
13 */
14
15 import { useState } from '@wordpress/element';
16 import apiFetch from '@wordpress/api-fetch';
17 import {
18 Button,
19 Card,
20 CardBody,
21 CardHeader,
22 Notice,
23 } from '@wordpress/components';
24 import { __, sprintf } from '@wordpress/i18n';
25
26 export default function Secrets( { rotatedAt } ) {
27 const [ isBusy, setBusy ] = useState( false );
28 const [ result, setResult ] = useState( null );
29 // The date arrives ready-formatted from the server. Formatting it here
30 // would use the reader's time zone and language instead of the site's, and
31 // the success message right above it is formatted with wp_date() -- two
32 // dates in the same card disagreeing by a day, on a card whose job is to
33 // make an unexpected date stand out.
34 const [ lastRotated, setLastRotated ] = useState( rotatedAt || '' );
35 const [ confirming, setConfirming ] = useState( false );
36
37 const rotate = () => {
38 setBusy( true );
39 setConfirming( false );
40
41 apiFetch( { path: '/cryptx/v1/secrets/rotate', method: 'POST' } )
42 .then( ( response ) => {
43 setResult( { status: 'success', text: response.message } );
44 setLastRotated( response.secretsRotatedAt || '' );
45 } )
46 .catch( ( error ) =>
47 setResult( {
48 status: 'error',
49 text:
50 error?.message ||
51 __( 'The secrets could not be replaced.', 'cryptx' ),
52 } )
53 )
54 .finally( () => setBusy( false ) );
55 };
56
57 return (
58 <Card className="cryptx-section">
59 <CardHeader>
60 <h2 className="cryptx-section__title">
61 { __( 'Encryption secrets', 'cryptx' ) }
62 </h2>
63 </CardHeader>
64 <CardBody>
65 <p>
66 { __(
67 "CryptX keeps two secrets. One is used to encrypt the links and travels inside each of them, so that a visitor's browser can open it. The other never leaves your server and stands in for the address when one is drawn as a picture.",
68 'cryptx'
69 ) }
70 </p>
71 <p>
72 { __(
73 'Replacing them is safe and rarely necessary — after restoring a backup that may have been seen by someone else, for instance. Links that are already published keep working, because each one carries the key it was made with. Pictures are opened on the server, so the old secret is kept for 30 days and the pictures in pages that are still cached go on working until then. Only one old secret is kept, so replacing them a second time inside those 30 days ends the grace period for the first — which is also how you cut it short deliberately, if the old secret needs to stop working now.',
74 'cryptx'
75 ) }
76 </p>
77
78 { lastRotated && (
79 <p className="cryptx-secrets__last">
80 { sprintf(
81 /* translators: %s: a date */
82 __( 'Last replaced on %s.', 'cryptx' ),
83 lastRotated
84 ) }
85 </p>
86 ) }
87
88 { result && (
89 <Notice
90 status={ result.status }
91 isDismissible={ false }
92 className="cryptx-secrets__notice"
93 >
94 { result.text }
95 </Notice>
96 ) }
97
98 { confirming ? (
99 <div className="cryptx-secrets__confirm">
100 <p>{ __( 'Replace both secrets now?', 'cryptx' ) }</p>
101 <Button
102 variant="primary"
103 isDestructive
104 onClick={ rotate }
105 isBusy={ isBusy }
106 disabled={ isBusy }
107 __next40pxDefaultSize
108 >
109 { __( 'Yes, replace them', 'cryptx' ) }
110 </Button>
111 <Button
112 variant="tertiary"
113 onClick={ () => setConfirming( false ) }
114 disabled={ isBusy }
115 __next40pxDefaultSize
116 >
117 { __( 'Cancel', 'cryptx' ) }
118 </Button>
119 </div>
120 ) : (
121 <Button
122 variant="secondary"
123 onClick={ () => setConfirming( true ) }
124 disabled={ isBusy }
125 __next40pxDefaultSize
126 >
127 { __( 'Create new secrets', 'cryptx' ) }
128 </Button>
129 ) }
130 </CardBody>
131 </Card>
132 );
133 }
134