Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LivenessDetect: @smithy/util-base64: toBase64 encoder function only accepts string | Uint8Array. #5057

Closed
4 tasks done
lwin-kyaw opened this issue Mar 11, 2024 · 5 comments
Closed
4 tasks done
Labels
Liveness not-reproducible Not able to reproduce the issue

Comments

@lwin-kyaw
Copy link

Before creating a new issue, please confirm:

On which framework/platform are you having an issue?

React

Which UI component?

Liveness

How is your app built?

Webpack 5

What browsers are you seeing the problem on?

Chrome, Firefox, Safari

Which region are you seeing the problem in?

ap-south-1

Please describe your bug.

Hi, I'm not sure whether this is doable or not.
To give you the context, what I'm trying to do is exporting the liveness check react component as a webpack bundle and use it in the other projects.
However, I'm getting this error when using @aws-amplify/ui-react-liveness,

@smithy/util-base64: toBase64 encoder function only accepts string | Uint8Array.

during the liveness analysis (video stream).
The error occurs during the call to the aws start-face-liveness-session-websocket session (during the series of light flashes).

What's the expected behaviour?

Complete the liveness analysis and get the result from the Liveness session.

Help us reproduce the bug!

Bundle the liveness-check component with webpack 5 and import it to the another project. Start the liveness analysis.

Code Snippet

Exposed class to the other projects

/**
 * entry point of the webpack bundle
 * # example usage
 * const livenessUI = new LivenessUI({ language: "en"});
 * livenessUI.init();
**/
class LivenessUI {
  private language: string;

  constructor(config?: LivenessUIConfig) {
    this.language = config?.language || "en";
  }

  setLanguage(lang: string): void {
    this.language = lang;
  }

  // attach this method to button click or some HTML event
  // upon firing this method, `LivenessCheck` component will be mounted to the UI (DOM)
  init(): void {
    const container = this.createWrapper("100");
    const mountPoint = ReactDOMClient.createRoot(container);
    mountPoint.render(<LivenessCheck language={this.language} />);
  }

  private createWrapper(parentZIndex: string): HTMLElement {
    const existingWrapper = document.getElementById("liveness-container");
    if (existingWrapper) existingWrapper.remove();
    const parent = document.createElement("section");
    parent.classList.add("liveness-container");
    parent.setAttribute("id", "liveness-container");
    parent.style.zIndex = parentZIndex;
    parent.style.position = "relative";
    const wrapper = document.createElement("section");
    wrapper.setAttribute("id", "liveness-container");
    parent.appendChild(wrapper);
    document.body.appendChild(parent);
    return wrapper;
  }
}

export default LivenessUI;

React Component

// Liveness Check Component
export function LivenessAnalysis({ onCompleteAnalysis, language }: ILivenessProps) {
  const [loading, setLoading] = useState<boolean>(true);
  const [sessionId, setSessionId] = useState<string | null>(null);
  const [success, setSuccess] = useState("");

  const fetchCreateLiveness = useCallback(async () => {
    const response = await fetch(`${LIVENESS_API_ENDPOINT}/create-session`);
    const data = (await response.json()) as { sessionId: string };
    log.info("json", data);
    console.log("json", data);
    if (data.sessionId) {
      setSessionId(data.sessionId);
    } else {
      onCompleteAnalysis("Failed", "failed to create liveness-session");
    }
    setLoading(false);
  }, [onCompleteAnalysis]);

  useEffect(() => {
    fetchCreateLiveness();
  }, [fetchCreateLiveness]);

  const handleAnalysisComplete = async () => {
    if (sessionId) {
      const url = `${LIVENESS_API_ENDPOINT}/session-result?sessionId=${sessionId}`;
      const response = await fetch(url);

      const data = await response.json();
      log.info(data);
      if (data.response.isLive) {
        setSuccess("Liveness check success");
      } else {
        setSuccess("Liveness check failed");
      }
      onCompleteAnalysis(data.response.isLive ? "Success" : "Failed");
    }
  };

  const handleOnUserCancel = () => {
    log.info("handleOnUserCancel");
    onCompleteAnalysis("Cancelled");
  };
  if (loading || !sessionId) {
    return <Loader />;
  }
  return (
    <div>
      <FaceLivenessDetector
        sessionId={sessionId}
        region="ap-south-1"
        onAnalysisComplete={handleAnalysisComplete}
        onError={(error) => {
          log.error(error);
          onCompleteAnalysis("Failed", error.error.message);
        }}
        onUserCancel={handleOnUserCancel}
        displayText={livenessDisplayTexts(language)}
      />
      <Heading level={2}>{success}</Heading>
    </div>
  );
}

Console log output

Screenshot 2024-03-11 at 11 47 38

Additional information and screenshots

Relevant deps in package.json

"name": "liveness-ui",
"dependencies": {
    "@aws-amplify/ui-react": "^6.1.5",
    "@aws-amplify/ui-react-liveness": "^3.0.11",
    "aws-amplify": "^6.0.16",
    "react": "^18.x",
    "react-dom": "^18.x",
    "react-i18next": "^13.5.0",
    "typescript": "^5.4.2",
  },

webpack.config.js (I've removed some redundant snippets)

module.exports = {
  entry: "./src/index.ts",
  target: "web",
  output: {
     path: path.resolve(__dirname, "dist"),
     .... 
  },
  module: [
    ....
    {
      test: /(ts|js)x?$/,
      exclude: /node_modules/,
      use: "babel-loader",
    }
    ....
  ],
}

Usage in the other project

// tsx
import LivenessUI from "liveness-ui";

function MyComponent() {
    const livenessUI = new LivenessUI();
    
    function onInitUI() {
        livenessUI.init({language: "en"});
    }
   
   return (
      <div>
           ....
          <button on-click={onInitUI}>Init livness</button>
           ....
      </div>
   )
}
@github-actions github-actions bot added the pending-triage Issue is pending triage label Mar 11, 2024
@akabiria
Copy link

I am experiencing the same exact issue after updating my packages.

On which framework/platform are you having an issue?
React Remix Run

Which UI component?
Liveness

How is your app built?
Remix Build

What browsers are you seeing the problem on?
Chrome, Firefox, Safari

Which region are you seeing the problem in?
us-west-2

Please describe your bug.
I am experiencing the same exact issue. It happens during liveness check analysis

@esauerbo
Copy link
Contributor

Hi @lwin-kyaw thanks for including all these details. Looking at the LivenessUI class, where is the LivenessCheck component coming from? Are you able to provide a minimum reproducible example to help us recreate this error?

@esauerbo esauerbo added pending-response not-reproducible Not able to reproduce the issue Liveness and removed pending-triage Issue is pending triage labels Mar 11, 2024
@lwin-kyaw
Copy link
Author

Hi @esauerbo, thanks for the reply.

The below are the implementations of the components.

LivenessCheck.tsx

// imports
....
Amplify.configure(awsexports);

export default function LivenessCheck({
  language = "en",
}: LivenessCheckProps) {
  const [livnessResult, setLivenessResult] = useState<AnalysisResult | null>(null);
  const [analysisStatus, setAnalysisStatus] = useState<string | undefined>();

  const onTryAgain = () => {
    setLivenessResult(null);
  };

  const onCompleteAnalysis = (result: AnalysisResult, error?: string) => {
    setLivenessResult(result);
    setAnalysisStatus(error);
  };

  return (
    <ThemeProvider>
      {livnessResult ? (
        <Completion result={livnessResult} onTryAgain={onTryAgain} statusText={analysisStatus} />
      ) : (
        <LivenessAnalysis onCompleteAnalysis={onCompleteAnalysis} language={language} />
      )}
    </ThemeProvider>
  );
}

LivenessAnalysis.tsx

// Liveness Check Component
export function LivenessAnalysis({ onCompleteAnalysis, language }: ILivenessProps) {
  const [loading, setLoading] = useState<boolean>(true);
  const [sessionId, setSessionId] = useState<string | null>(null);
  const [success, setSuccess] = useState("");

  const fetchCreateLiveness = useCallback(async () => {
    const response = await fetch(`${LIVENESS_API_ENDPOINT}/create-session`);
    const data = (await response.json()) as { sessionId: string };
    log.info("json", data);
    console.log("json", data);
    if (data.sessionId) {
      setSessionId(data.sessionId);
    } else {
      onCompleteAnalysis("Failed", "failed to create liveness-session");
    }
    setLoading(false);
  }, [onCompleteAnalysis]);

  useEffect(() => {
    fetchCreateLiveness();
  }, [fetchCreateLiveness]);

  const handleAnalysisComplete = async () => {
    if (sessionId) {
      const url = `${LIVENESS_API_ENDPOINT}/session-result?sessionId=${sessionId}`;
      const response = await fetch(url);

      const data = await response.json();
      log.info(data);
      if (data.response.isLive) {
        setSuccess("Liveness check success");
      } else {
        setSuccess("Liveness check failed");
      }
      onCompleteAnalysis(data.response.isLive ? "Success" : "Failed");
    }
  };

  const handleOnUserCancel = () => {
    log.info("handleOnUserCancel");
    onCompleteAnalysis("Cancelled");
  };
  if (loading || !sessionId) {
    return <Loader />;
  }
  return (
    <div>
      <FaceLivenessDetector
        sessionId={sessionId}
        region="ap-south-1"
        onAnalysisComplete={handleAnalysisComplete}
        onError={(error) => {
          log.error(error);
          onCompleteAnalysis("Failed", error.error.message);
        }}
        onUserCancel={handleOnUserCancel}
        displayText={livenessDisplayTexts(language)}
      />
      <Heading level={2}>{success}</Heading>
    </div>
  );
}

@davesahaj
Copy link

I am facing the exact same issue while following these guides from official docs:

@esauerbo
Copy link
Contributor

Thanks for reporting this everyone. We have another issue tracking this: #5058 so closing this out as a duplicate.

Please see the new issue for a temporary workaround and future updates on a fix. Feel free to comment on that thread with any questions or issues you run into.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Liveness not-reproducible Not able to reproduce the issue
Projects
None yet
Development

No branches or pull requests

4 participants