amplify-js icon indicating copy to clipboard operation
amplify-js copied to clipboard

Using a fixed `clientId` with Amplify PubSub causes an infinite connection loop

Open massi-ang opened this issue 2 years ago • 4 comments

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

Authentication, PubSub

Amplify Categories

No response

Environment information

# Put output below this line
System:
    OS: macOS 13.5.2
    CPU: (10) arm64 Apple M1 Pro
    Memory: 293.23 MB / 32.00 GB
    Shell: 3.5.1 - /opt/homebrew/bin/fish
  Binaries:
    Node: 20.2.0 - ~/.volta/tools/image/node/20.2.0/bin/node
    Yarn: 1.22.19 - ~/.volta/tools/image/yarn/1.22.19/bin/yarn
    npm: 9.6.6 - ~/.volta/tools/image/node/20.2.0/bin/npm
    pnpm: 8.6.12 - ~/.volta/bin/pnpm
  Browsers:
    Chrome: 119.0.6045.159
    Edge: 119.0.2151.72
  npmPackages:
    @aws-amplify/pubsub: ^6.0.3 => 6.0.3
    @aws-amplify/ui-react: ^6.0.2 => 6.0.2
    @types/react: ^18.2.37 => 18.2.37
    @types/react-dom: ^18.2.15 => 18.2.15
    @typescript-eslint/eslint-plugin: ^6.10.0 => 6.10.0
    @typescript-eslint/parser: ^6.10.0 => 6.10.0
    @vitejs/plugin-react: ^4.2.0 => 4.2.0
    aws-amplify: ^6.0.3 => 6.0.3
    eslint: ^8.53.0 => 8.53.0
    eslint-plugin-react-hooks: ^4.6.0 => 4.6.0
    eslint-plugin-react-refresh: ^0.4.4 => 0.4.4
    react: ^18.2.0 => 18.2.0
    react-dom: ^18.2.0 => 18.2.0
    typescript: ^5.2.2 => 5.2.2
    vite: ^5.0.0 => 5.0.0
  npmGlobalPackages:
    corepack: 0.17.2
    npm: 9.6.6

Describe the bug

When setting the clientId in the PubSub client to a fixed value to enforce security best practices (such as creating a least privilege policy to limit the connection with a specific clientId only), the application enters an infinite connection loop, as the client tries to connect with the same ID causing a DUPLICATE_CLIENT_ID disconnection error.

Expected behavior

The client connects

Reproduction steps

Create a React app, add Amplify PubSub as per documentation Additionally set the clientId to a fixed value

Code Snippet

import { useEffect, useRef, useState } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import { PubSub } from '@aws-amplify/pubsub';
import '@aws-amplify/ui-react/styles.css';
import './App.css';
import { withAuthenticator } from '@aws-amplify/ui-react';
import { fetchAuthSession } from 'aws-amplify/auth';

function App() {
  const [count, setCount] = useState(0);
  const pubsub = useRef<PubSub | undefined>(undefined);

  useEffect(() => {
    console.log('Publishing ', count);
    pubsub.current
      ?.publish({
        topics: 'hello',
        message: { msg: `Hello ${count}` },
      })
      .catch((err) => console.error(err));
  }, [count]);

  useEffect(() => {
    fetchAuthSession().then((info) => {
      console.log(info.identityId);
      pubsub.current = new PubSub({
        endpoint: 'wss://xxxxxxxxxxx-ats.iot.eu-west-1.amazonaws.com/mqtt',
        region: 'eu-west-1',
        clientId: info.identityId,
      });

      pubsub.current.subscribe({ topics: [] }).subscribe({});
    });
  }, []);

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button
          onClick={async () => {
            setCount((count) => count + 1);
          }}
        >
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  );
}

export default withAuthenticator(App);

Log output

// Put your logs below this line

[DEBUG] 10:34.110 CognitoCredentialsProvider - returning stored credentials as they neither past TTL nor expired. [ConsoleLogger.ts:73:16](http://localhost:5173/node_modules/.pnpm/@[email protected]/node_modules/@aws-amplify/core/src/Logger/ConsoleLogger.ts)
[DEBUG] 10:34.115 MqttOverWS - Creating new MQTT client eu-west-1:d7a3b34e-819c-4ddb-ae5e-e191b758f168 [ConsoleLogger.ts:85:16](http://localhost:5173/node_modules/.pnpm/@[email protected]/node_modules/@aws-amplify/core/src/Logger/ConsoleLogger.ts)
[WARN] 10:34.432 MqttOverWS - eu-west-1:d7a3b34e-819c-4ddb-ae5e-e191b758f168 {
  "errorCode": 8,
  "errorMessage": "AMQJS0008I Socket closed.",
  "uri": "wss://acwprzq1nws9h-ats.iot.eu-west-1.amazonaws.com/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA2FVXUBKZBHRD5SFJ%2F20231120%2Feu-west-1%2Fiotdevicegateway%2Faws4_request&X-Amz-Date=20231120T121028Z&X-Amz-SignedHeaders=host&X-Amz-Signature=e2552f5f3144d9190da88d7a4bc72abb7a706a6a4792507d61ba6364fb2d770f&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEKT%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCWV1LXdlc3QtMSJIMEYCIQD25rEH%2F%2FpcfHGEdeyjJu2AXdEPHW8j9aVYgxTm%2FGYh3QIhAKdcP6F%2FPJcZE68gbdh8vuAs2XZb%2BVBeYqiUXp9ku3WfKs0ECO3%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQBBoMNjk5MzkxMDE5Njk4IgxKgx4AOEZaJThdLSkqoQSDfvHjGH98zYBNlt2wZDvmw2%2FjDuaKJxIiEXeK3UTSU%2BtFDcNKN5Pj%2BN169chO86TL121CaQt6S2%2B6p16z4jPFyVB0KLlPFTsuWqgi64VZTVJOoLvTRylrIK8VZc6VHgHKD7y23p0MmFJB10QUMz%2F7NDHzO%2Fvjg3JGF6tVDdRt36OR67rfzOGOFnZM9l6Q5LBgidN9y3tS%2Fwg2taAlElHLa592Ohg0w0PuKsTVro5QBOqiN77gw8f4GVgi0rC%2BLNsF7MvPGxuS8CSL%2BYlKAfMHJqcO7ZPHpWNmys7tewFxyBK4mQfpZ0HeQb1ax0Vz%2BvzK5OLBteW2K7VqAUhbr6JStz6pVAABi6gPO1tGEhrHPGuPrc8j2lNQCnztDENO7t0z%2BWoQ7QqPOav8I%2BWyDR0Nn%2FeSvpDoWkYUcD5r6nKHZ7HYxWw%2FH7qGdNYQ%2F5UlkyDjo7IlrVN1dFDcbb3aiRrxec48j7I4P9JPPOtT08PVca2l37O997%2FRbFWIBKMFSYmpm2%2B8UV63EAicyb8vqvsXDa6N0caCZmEbqt9SrF5GUrE%2BgkNP0VHs6MLo%2BEuKyZn7wWQ5CT1RbzlskrSMGm7o1PVoWIkZ0uSUFs8W8MLbabjEiPvRLNVTv5W6oZCIamrj3idkM9ZflWPhZc4IiEJM3xN%2FN%2BTwKLdOdaXiNXSl8WGSGQnTHcOWJzTYQQmV9k6cmWVc8vTMFsw7CcsNIpNfWDCUme2qBjqEAkmlogynGVgP9TaciKcZ7Fmi2%2B1Q9kZ%2FNVTFwVCjPUj%2BJeV%2BZFX1dlBv4DH1FHBT3DG%2BCDfHnkuMeooLcmOdCfOrGa8%2BpaOYE6uw34OqZou4ofjgZNF8OkMgDYMohPX%2Bo%2FDetK8LDC8TyIZ15YQhpa8mWarN8h3l6v4H2Wrqo15AR0TsA61xGI%2BIaOVx0DIx1co4R47nVRDw9bGIhYqLW6zru%2BdGWlJBNx82Kxm4%2BaXvtY%2B63EypQ%2F4owh1lN1E8vm2%2F47aMW1Ry4vzUU9OX%2BzwEtm4vSfubsHhhvP5%2FIsB0Tk%2FW%2BVBC%2Fu82pEjmE2AtDPq6RS%2FSbYEF4W1dHoT8J1U07AXC"
} [localhost:5173:12966:25](http://localhost:5173/)
[DEBUG] 10:39.439 CognitoCredentialsProvider - returning stored credentials as they neither past TTL nor expired. [ConsoleLogger.ts:73:16](http://localhost:5173/node_modules/.pnpm/@[email protected]/node_modules/@aws-amplify/core/src/Logger/ConsoleLogger.ts)
[DEBUG] 10:39.440 MqttOverWS - Creating new MQTT client eu-west-1:d7a3b34e-819c-4ddb-ae5e-e191b758f168 [ConsoleLogger.ts:85:16](http://localhost:5173/node_modules/.pnpm/@[email protected]/node_modules/@aws-amplify/core/src/Logger/ConsoleLogger.ts)
[WARN] 10:39.651 MqttOverWS - eu-west-1:d7a3b34e-819c-4ddb-ae5e-e191b758f168 {
  "errorCode": 8,
  "errorMessage": "AMQJS0008I Socket closed.",
  "uri": "wss://acwprzq1nws9h-ats.iot.eu-west-1.amazonaws.com/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA2FVXUBKZBHRD5SFJ%2F20231120%2Feu-west-1%2Fiotdevicegateway%2Faws4_request&X-Amz-Date=20231120T121034Z&X-Amz-SignedHeaders=host&X-Amz-Signature=648852b828705255ad8652f5727a0acc34a3ec300dbff1893152b961fc98d081&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEKT%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCWV1LXdlc3QtMSJIMEYCIQD25rEH%2F%2FpcfHGEdeyjJu2AXdEPHW8j9aVYgxTm%2FGYh3QIhAKdcP6F%2FPJcZE68gbdh8vuAs2XZb%2BVBeYqiUXp9ku3WfKs0ECO3%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQBBoMNjk5MzkxMDE5Njk4IgxKgx4AOEZaJThdLSkqoQSDfvHjGH98zYBNlt2wZDvmw2%2FjDuaKJxIiEXeK3UTSU%2BtFDcNKN5Pj%2BN169chO86TL121CaQt6S2%2B6p16z4jPFyVB0KLlPFTsuWqgi64VZTVJOoLvTRylrIK8VZc6VHgHKD7y23p0MmFJB10QUMz%2F7NDHzO%2Fvjg3JGF6tVDdRt36OR67rfzOGOFnZM9l6Q5LBgidN9y3tS%2Fwg2taAlElHLa592Ohg0w0PuKsTVro5QBOqiN77gw8f4GVgi0rC%2BLNsF7MvPGxuS8CSL%2BYlKAfMHJqcO7ZPHpWNmys7tewFxyBK4mQfpZ0HeQb1ax0Vz%2BvzK5OLBteW2K7VqAUhbr6JStz6pVAABi6gPO1tGEhrHPGuPrc8j2lNQCnztDENO7t0z%2BWoQ7QqPOav8I%2BWyDR0Nn%2FeSvpDoWkYUcD5r6nKHZ7HYxWw%2FH7qGdNYQ%2F5UlkyDjo7IlrVN1dFDcbb3aiRrxec48j7I4P9JPPOtT08PVca2l37O997%2FRbFWIBKMFSYmpm2%2B8UV63EAicyb8vqvsXDa6N0caCZmEbqt9SrF5GUrE%2BgkNP0VHs6MLo%2BEuKyZn7wWQ5CT1RbzlskrSMGm7o1PVoWIkZ0uSUFs8W8MLbabjEiPvRLNVTv5W6oZCIamrj3idkM9ZflWPhZc4IiEJM3xN%2FN%2BTwKLdOdaXiNXSl8WGSGQnTHcOWJzTYQQmV9k6cmWVc8vTMFsw7CcsNIpNfWDCUme2qBjqEAkmlogynGVgP9TaciKcZ7Fmi2%2B1Q9kZ%2FNVTFwVCjPUj%2BJeV%2BZFX1dlBv4DH1FHBT3DG%2BCDfHnkuMeooLcmOdCfOrGa8%2BpaOYE6uw34OqZou4ofjgZNF8OkMgDYMohPX%2Bo%2FDetK8LDC8TyIZ15YQhpa8mWarN8h3l6v4H2Wrqo15AR0TsA61xGI%2BIaOVx0DIx1co4R47nVRDw9bGIhYqLW6zru%2BdGWlJBNx82Kxm4%2BaXvtY%2B63EypQ%2F4owh1lN1E8vm2%2F47aMW1Ry4vzUU9OX%2BzwEtm4vSfubsHhhvP5%2FIsB0Tk%2FW%2BVBC%2Fu82pEjmE2AtDPq6RS%2FSbYEF4W1dHoT8J1U07AXC"
} [localhost:5173:12966:25](http://localhost:5173/)
[DEBUG] 10:44.658 CognitoCredentialsProvider - returning stored credentials as they neither past TTL nor expired. [ConsoleLogger.ts:73:16](http://localhost:5173/node_modules/.pnpm/@[email protected]/node_modules/@aws-amplify/core/src/Logger/ConsoleLogger.ts)
[DEBUG] 10:44.660 MqttOverWS - Creating new MQTT client eu-west-1:d7a3b34e-819c-4ddb-ae5e-e191b758f168 [ConsoleLogger.ts:85:16](http://localhost:5173/node_modules/.pnpm/@[email protected]/node_modules/@aws-amplify/core/src/Logger/ConsoleLogger.ts)
[WARN] 10:44.868 MqttOverWS - eu-west-1:d7a3b34e-819c-4ddb-ae5e-e191b758f168 {
  "errorCode": 8,
  "errorMessage": "AMQJS0008I Socket closed.",
  "uri": "wss://acwprzq1nws9h-ats.iot.eu-west-1.amazonaws.com/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA2FVXUBKZBHRD5SFJ%2F20231120%2Feu-west-1%2Fiotdevicegateway%2Faws4_request&X-Amz-Date=20231120T121039Z&X-Amz-SignedHeaders=host&X-Amz-Signature=1006ae47ccdaa5c0f689ee67c54feb3ef274e48543a22d733ba8992d7ce7c196&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEKT%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCWV1LXdlc3QtMSJIMEYCIQD25rEH%2F%2FpcfHGEdeyjJu2AXdEPHW8j9aVYgxTm%2FGYh3QIhAKdcP6F%2FPJcZE68gbdh8vuAs2XZb%2BVBeYqiUXp9ku3WfKs0ECO3%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQBBoMNjk5MzkxMDE5Njk4IgxKgx4AOEZaJThdLSkqoQSDfvHjGH98zYBNlt2wZDvmw2%2FjDuaKJxIiEXeK3UTSU%2BtFDcNKN5Pj%2BN169chO86TL121CaQt6S2%2B6p16z4jPFyVB0KLlPFTsuWqgi64VZTVJOoLvTRylrIK8VZc6VHgHKD7y23p0MmFJB10QUMz%2F7NDHzO%2Fvjg3JGF6tVDdRt36OR67rfzOGOFnZM9l6Q5LBgidN9y3tS%2Fwg2taAlElHLa592Ohg0w0PuKsTVro5QBOqiN77gw8f4GVgi0rC%2BLNsF7MvPGxuS8CSL%2BYlKAfMHJqcO7ZPHpWNmys7tewFxyBK4mQfpZ0HeQb1ax0Vz%2BvzK5OLBteW2K7VqAUhbr6JStz6pVAABi6gPO1tGEhrHPGuPrc8j2lNQCnztDENO7t0z%2BWoQ7QqPOav8I%2BWyDR0Nn%2FeSvpDoWkYUcD5r6nKHZ7HYxWw%2FH7qGdNYQ%2F5UlkyDjo7IlrVN1dFDcbb3aiRrxec48j7I4P9JPPOtT08PVca2l37O997%2FRbFWIBKMFSYmpm2%2B8UV63EAicyb8vqvsXDa6N0caCZmEbqt9SrF5GUrE%2BgkNP0VHs6MLo%2BEuKyZn7wWQ5CT1RbzlskrSMGm7o1PVoWIkZ0uSUFs8W8MLbabjEiPvRLNVTv5W6oZCIamrj3idkM9ZflWPhZc4IiEJM3xN%2FN%2BTwKLdOdaXiNXSl8WGSGQnTHcOWJzTYQQmV9k6cmWVc8vTMFsw7CcsNIpNfWDCUme2qBjqEAkmlogynGVgP9TaciKcZ7Fmi2%2B1Q9kZ%2FNVTFwVCjPUj%2BJeV%2BZFX1dlBv4DH1FHBT3DG%2BCDfHnkuMeooLcmOdCfOrGa8%2BpaOYE6uw34OqZou4ofjgZNF8OkMgDYMohPX%2Bo%2FDetK8LDC8TyIZ15YQhpa8mWarN8h3l6v4H2Wrqo15AR0TsA61xGI%2BIaOVx0DIx1co4R47nVRDw9bGIhYqLW6zru%2BdGWlJBNx82Kxm4%2BaXvtY%2B63EypQ%2F4owh1lN1E8vm2%2F47aMW1Ry4vzUU9OX%2BzwEtm4vSfubsHhhvP5%2FIsB0Tk%2FW%2BVBC%2Fu82pEjmE2AtDPq6RS%2FSbYEF4W1dHoT8J1U07AXC"
} [localhost:5173:12966:25](http://localhost:5173/)
[DEBUG] 10:49.874 CognitoCredentialsProvider - returning stored credentials as they neither past TTL nor expired. [ConsoleLogger.ts:73:16](http://localhost:5173/node_modules/.pnpm/@[email protected]/node_modules/@aws-amplify/core/src/Logger/ConsoleLogger.ts)
[DEBUG] 10:49.875 MqttOverWS - Creating new MQTT client eu-west-1:d7a3b34e-819c-4ddb-ae5e-e191b758f168 [ConsoleLogger.ts:85:16](http://localhost:5173/node_modules/.pnpm/@[email protected]/node_modules/@aws-amplify/core/src/Logger/ConsoleLogger.ts)
[WARN] 10:50.87 MqttOverWS - eu-west-1:d7a3b34e-819c-4ddb-ae5e-e191b758f168 {
  "errorCode": 8,
  "errorMessage": "AMQJS0008I Socket closed.",
  "uri": "wss://acwprzq1nws9h-ats.iot.eu-west-1.amazonaws.com/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA2FVXUBKZBHRD5SFJ%2F20231120%2Feu-west-1%2Fiotdevicegateway%2Faws4_request&X-Amz-Date=20231120T121044Z&X-Amz-SignedHeaders=host&X-Amz-Signature=783590327095272abf8427dc992f2eb6f9ed805b34ead76c9c44ef58626e1b41&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEKT%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCWV1LXdlc3QtMSJIMEYCIQD25rEH%2F%2FpcfHGEdeyjJu2AXdEPHW8j9aVYgxTm%2FGYh3QIhAKdcP6F%2FPJcZE68gbdh8vuAs2XZb%2BVBeYqiUXp9ku3WfKs0ECO3%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQBBoMNjk5MzkxMDE5Njk4IgxKgx4AOEZaJThdLSkqoQSDfvHjGH98zYBNlt2wZDvmw2%2FjDuaKJxIiEXeK3UTSU%2BtFDcNKN5Pj%2BN169chO86TL121CaQt6S2%2B6p16z4jPFyVB0KLlPFTsuWqgi64VZTVJOoLvTRylrIK8VZc6VHgHKD7y23p0MmFJB10QUMz%2F7NDHzO%2Fvjg3JGF6tVDdRt36OR67rfzOGOFnZM9l6Q5LBgidN9y3tS%2Fwg2taAlElHLa592Ohg0w0PuKsTVro5QBOqiN77gw8f4GVgi0rC%2BLNsF7MvPGxuS8CSL%2BYlKAfMHJqcO7ZPHpWNmys7tewFxyBK4mQfpZ0HeQb1ax0Vz%2BvzK5OLBteW2K7VqAUhbr6JStz6pVAABi6gPO1tGEhrHPGuPrc8j2lNQCnztDENO7t0z%2BWoQ7QqPOav8I%2BWyDR0Nn%2FeSvpDoWkYUcD5r6nKHZ7HYxWw%2FH7qGdNYQ%2F5UlkyDjo7IlrVN1dFDcbb3aiRrxec48j7I4P9JPPOtT08PVca2l37O997%2FRbFWIBKMFSYmpm2%2B8UV63EAicyb8vqvsXDa6N0caCZmEbqt9SrF5GUrE%2BgkNP0VHs6MLo%2BEuKyZn7wWQ5CT1RbzlskrSMGm7o1PVoWIkZ0uSUFs8W8MLbabjEiPvRLNVTv5W6oZCIamrj3idkM9ZflWPhZc4IiEJM3xN%2FN%2BTwKLdOdaXiNXSl8WGSGQnTHcOWJzTYQQmV9k6cmWVc8vTMFsw7CcsNIpNfWDCUme2qBjqEAkmlogynGVgP9TaciKcZ7Fmi2%2B1Q9kZ%2FNVTFwVCjPUj%2BJeV%2BZFX1dlBv4DH1FHBT3DG%2BCDfHnkuMeooLcmOdCfOrGa8%2BpaOYE6uw34OqZou4ofjgZNF8OkMgDYMohPX%2Bo%2FDetK8LDC8TyIZ15YQhpa8mWarN8h3l6v4H2Wrqo15AR0TsA61xGI%2BIaOVx0DIx1co4R47nVRDw9bGIhYqLW6zru%2BdGWlJBNx82Kxm4%2BaXvtY%2B63EypQ%2F4owh1lN1E8vm2%2F47aMW1Ry4vzUU9OX%2BzwEtm4vSfubsHhhvP5%2FIsB0Tk%2FW%2BVBC%2Fu82pEjmE2AtDPq6RS%2FSbYEF4W1dHoT8J1U07AXC"
} [localhost:5173:12966:25](http://localhost:5173/)

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

massi-ang avatar Nov 20 '23 12:11 massi-ang

In addition to this, it would be useful to provide a disconnect() method on the PubSub object to be able to clean up resources.

massi-ang avatar Nov 20 '23 12:11 massi-ang

@massi-ang, thank you for opening this issue. Was this an existing app that you migrated/updated to the newly released v6 and experienced this? Or was this a freshly built app using v6?

cwomack avatar Nov 22 '23 15:11 cwomack

This was a new testing app I created, and basically consists of only that App.tsx file

massi-ang avatar Nov 22 '23 16:11 massi-ang

Hi @massi-ang,

Thank you for prividing the detailed code snippet. It helps a lot! We are currently investigating the issue and will keep you post in this threat.

AllanZhengYP avatar Apr 25 '24 00:04 AllanZhengYP