Remove crypto dependency
Summary: Remove crypto dep, which was only used by NUX, to hash the elements that has been confirmed. Sadly trickier than hoped; there is no uniform api in both browser and Node available that can take a sha-256 hash, and the browser APIs are async. Reviewed By: aigoncharov Differential Revision: D32721204 fbshipit-source-id: 32625f83bf6c60cedc4fb7096240c2fa0d8434a7
This commit is contained in:
committed by
Facebook GitHub Bot
parent
058785a509
commit
f5f9608098
@@ -7,7 +7,13 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import React, {createContext, useCallback, useContext} from 'react';
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import {Badge, Tooltip, Typography, Button} from 'antd';
|
||||
import styled from '@emotion/styled';
|
||||
import {keyframes} from '@emotion/css';
|
||||
@@ -17,11 +23,11 @@ import {createState, useValue} from '../state/atom';
|
||||
import {SandyDevicePluginInstance} from '../plugin/DevicePlugin';
|
||||
import {Layout} from './Layout';
|
||||
import {BulbTwoTone} from '@ant-design/icons';
|
||||
import {createHash} from 'crypto';
|
||||
import type {TooltipPlacement} from 'antd/lib/tooltip';
|
||||
import {SandyPluginInstance} from '../plugin/Plugin';
|
||||
import {theme} from './theme';
|
||||
import {Tracked} from './Tracked';
|
||||
import {sha256} from '../utils/sha256';
|
||||
|
||||
const {Text} = Typography;
|
||||
|
||||
@@ -29,13 +35,12 @@ type NuxManager = ReturnType<typeof createNuxManager>;
|
||||
|
||||
const storageKey = `FLIPPER_NUX_STATE`;
|
||||
|
||||
export function getNuxKey(
|
||||
export async function getNuxKey(
|
||||
elem: React.ReactNode,
|
||||
currentPlugin?: SandyPluginInstance | SandyDevicePluginInstance,
|
||||
) {
|
||||
return `${currentPlugin?.definition.id ?? 'flipper'}:${createHash('sha256')
|
||||
.update(reactElementToJSXString(elem))
|
||||
.digest('base64')}`;
|
||||
): Promise<string> {
|
||||
const hash = await sha256(reactElementToJSXString(elem));
|
||||
return `${currentPlugin?.definition.id ?? 'flipper'}:${hash}`;
|
||||
}
|
||||
|
||||
export function createNuxManager() {
|
||||
@@ -52,18 +57,18 @@ export function createNuxManager() {
|
||||
}
|
||||
|
||||
return {
|
||||
markRead(
|
||||
async markRead(
|
||||
elem: React.ReactNode,
|
||||
currentPlugin?: SandyPluginInstance | SandyDevicePluginInstance,
|
||||
): void {
|
||||
readMap[getNuxKey(elem, currentPlugin)] = true;
|
||||
): Promise<void> {
|
||||
readMap[await getNuxKey(elem, currentPlugin)] = true;
|
||||
save();
|
||||
},
|
||||
isRead(
|
||||
async isRead(
|
||||
elem: React.ReactNode,
|
||||
currentPlugin?: SandyPluginInstance | SandyDevicePluginInstance,
|
||||
): boolean {
|
||||
return !!readMap[getNuxKey(elem, currentPlugin)];
|
||||
): Promise<boolean> {
|
||||
return !!readMap[await getNuxKey(elem, currentPlugin)];
|
||||
},
|
||||
resetHints(): void {
|
||||
readMap = {};
|
||||
@@ -74,8 +79,8 @@ export function createNuxManager() {
|
||||
}
|
||||
|
||||
const stubManager: NuxManager = {
|
||||
markRead() {},
|
||||
isRead() {
|
||||
async markRead() {},
|
||||
async isRead() {
|
||||
return true;
|
||||
},
|
||||
resetHints() {},
|
||||
@@ -100,7 +105,18 @@ export function NUX({
|
||||
const pluginInstance = useContext(SandyPluginContext);
|
||||
// changing the ticker will force `isRead` to be recomputed
|
||||
const _tick = useValue(manager.ticker);
|
||||
const isRead = manager.isRead(title, pluginInstance);
|
||||
// start with Read = true until proven otherwise, to avoid Nux glitches
|
||||
const [isRead, setIsRead] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
manager
|
||||
.isRead(title, pluginInstance)
|
||||
.then(setIsRead)
|
||||
.catch((e) => {
|
||||
console.warn('Failed to read NUX status', e);
|
||||
});
|
||||
}, [manager, title, pluginInstance, _tick]);
|
||||
|
||||
const dismiss = useCallback(() => {
|
||||
manager.markRead(title, pluginInstance);
|
||||
}, [title, manager, pluginInstance]);
|
||||
|
||||
@@ -11,25 +11,23 @@ import {TestUtils} from '../../';
|
||||
import React from 'react';
|
||||
import {getNuxKey} from '../NUX';
|
||||
|
||||
test('nuxkey computation', () => {
|
||||
expect(getNuxKey('test')).toMatchInlineSnapshot(
|
||||
`"flipper:n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="`,
|
||||
);
|
||||
expect(getNuxKey('test')).toMatchInlineSnapshot(
|
||||
`"flipper:n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="`,
|
||||
);
|
||||
expect(getNuxKey('test2')).toMatchInlineSnapshot(
|
||||
`"flipper:YDA64iuZiGG847KPM+7BvnWKITyGyTwHbb6fVYwRx1I="`,
|
||||
);
|
||||
expect(getNuxKey(<div>bla</div>)).toMatchInlineSnapshot(
|
||||
`"flipper:myN0Mqqzs3fPwYDKGEQVG9XD9togJNWYJiy1VNQOf18="`,
|
||||
);
|
||||
expect(getNuxKey(<div>bla2</div>)).toMatchInlineSnapshot(
|
||||
`"flipper:B6kICeYCJMWeUThs5TWCLuiwCqzr5cWn67xXA4ET0bU="`,
|
||||
);
|
||||
test('nuxkey computation', async () => {
|
||||
// Not a very good test, as our hashing api's are not available in Node...
|
||||
expect(await getNuxKey('test')).toMatchInlineSnapshot(`"flipper:test"`);
|
||||
expect(await getNuxKey('test2')).toMatchInlineSnapshot(`"flipper:test2"`);
|
||||
expect(await getNuxKey(<div>bla</div>)).toMatchInlineSnapshot(`
|
||||
"flipper:<div>
|
||||
bla
|
||||
</div>"
|
||||
`);
|
||||
expect(await getNuxKey(<div>bla2</div>)).toMatchInlineSnapshot(`
|
||||
"flipper:<div>
|
||||
bla2
|
||||
</div>"
|
||||
`);
|
||||
});
|
||||
|
||||
test('nuxkey computation with plugin', () => {
|
||||
test('nuxkey computation with plugin', async () => {
|
||||
const res = TestUtils.startPlugin({
|
||||
Component() {
|
||||
return null;
|
||||
@@ -40,8 +38,6 @@ test('nuxkey computation with plugin', () => {
|
||||
});
|
||||
|
||||
expect(
|
||||
getNuxKey('test', (res as any)._backingInstance),
|
||||
).toMatchInlineSnapshot(
|
||||
`"TestPlugin:n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="`,
|
||||
);
|
||||
await getNuxKey('test', (res as any)._backingInstance),
|
||||
).toMatchInlineSnapshot(`"TestPlugin:test"`);
|
||||
});
|
||||
|
||||
23
desktop/flipper-plugin/src/utils/sha256.tsx
Normal file
23
desktop/flipper-plugin/src/utils/sha256.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
export function sha256(message: string): Promise<string> {
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
return Promise.resolve(message.substr(0, 100));
|
||||
}
|
||||
// From https://stackoverflow.com/a/48161723/1983583
|
||||
const msgBuffer = new TextEncoder().encode(message);
|
||||
return crypto.subtle.digest('SHA-256', msgBuffer).then((hashBuffer) => {
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
const hashHex = hashArray
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('');
|
||||
return hashHex;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user