-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
52 additions
and
93 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
46 changes: 25 additions & 21 deletions
46
embed-sdk-react/docs/basic-examples/app/examples/basic-example/basic-example-wrapper.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,33 @@ | ||
// basic-example-wrapper.tsx | ||
// The SignedIframe component is responsible for securely embedding a Sigma Computing dashboard into a React application. | ||
// signEmbedUrl: This function is imported from the Sigma Embed SDK library and is used to generate a signed URL for secure access to a Sigma dashboard. | ||
"use client"; // This directive tells Next.js to treat this as a Client Component | ||
|
||
// Import the signEmbedUrl function from the utilities module | ||
import { useEffect, useState } from "react"; | ||
import { signEmbedUrl } from "@/lib/utils"; | ||
// Import the BasicExample component, which is responsible for rendering the iframe | ||
import BasicExample from "./basic-example-embed"; | ||
|
||
// Define an asynchronous component to sign the URL and render the iframe | ||
export default async function SignedIframe() { | ||
// Get the base URL from the environment variable | ||
const src = process.env.EMBED_URL || ""; // Use the value from the .env file | ||
export default function SignedIframe() { | ||
const [signedSrc, setSignedSrc] = useState<string | null>(null); | ||
const [error, setError] = useState<string | null>(null); | ||
const src = "https://app.sigmacomputing.com/embed/1-24vP6WRI5BK8C8dLX4kzac"; // Hardcoded URL as discussed | ||
|
||
try { | ||
// Await the signed URL by passing the base URL to the signEmbedUrl function | ||
const signedSrc = await signEmbedUrl(src); | ||
useEffect(() => { | ||
const getSignedUrl = async () => { | ||
try { | ||
const signedUrl = await signEmbedUrl(src); | ||
console.log("Signed URL:", signedUrl); | ||
setSignedSrc(signedUrl); // Set the signed URL in state | ||
} catch (err) { | ||
console.error("Error signing URL:", err); | ||
setError("Error loading iframe"); | ||
} | ||
}; | ||
|
||
// Log the base and signed URLs as output in server-side terminal session | ||
console.log("Signed URL:", signedSrc); | ||
getSignedUrl(); // Call the async function to sign the URL | ||
}, [src]); // Empty dependency array since `src` is hardcoded and won't change | ||
|
||
// Return the BasicExample component with the signed URL as a prop | ||
return <BasicExample src={signedSrc} />; | ||
} catch (error) { | ||
// Log any errors encountered during signing | ||
console.error("Error signing URL:", error); | ||
return <p>Error loading iframe</p>; | ||
} | ||
} | ||
// Conditional rendering based on signing state | ||
if (error) return <p>{error}</p>; | ||
if (!signedSrc) return <p>Loading...</p>; | ||
|
||
return <BasicExample src={signedSrc} />; // Pass signed URL to the iframe component | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,84 +2,62 @@ import { type ClassValue, clsx } from "clsx"; | |
import { twMerge } from "tailwind-merge"; | ||
import { v4 as uuid } from "uuid"; | ||
|
||
// Hardcoded Embed Configuration and User-Specific Values | ||
const EMBED_PATH = "your_sigma_url_to_embed"; | ||
const CLIENT_ID = "your_client_id"; | ||
const SECRET = "your_secret"; | ||
const EMAIL = "your_test_embed_user_email"; | ||
const EXTERNAL_USER_ID = "123"; | ||
const ACCOUNT_TYPE = “viewer"; | ||
const EXTERNAL_USER_TEAM = "your_team"; | ||
const SESSION_LENGTH = "3600"; // Default session length | ||
|
||
export function cn(...inputs: ClassValue[]) { | ||
return twMerge(clsx(inputs)); | ||
} | ||
|
||
/** | ||
* Buffer to hex string: | ||
* - convert buffer to byte array | ||
* - convert bytes to hex string | ||
* @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string | ||
*/ | ||
export function bufferToHex(buffer: ArrayBuffer) { | ||
return Array.from(new Uint8Array(buffer)) | ||
.map((b) => b.toString(16).padStart(2, "0")) | ||
.join(""); | ||
} | ||
|
||
/** | ||
* Uses Web Crypto API to create a SHA256 HMAC hex string. | ||
*/ | ||
async function simpleHmac({ key, data }: { key: string; data: string }) { | ||
const encoder = new TextEncoder(); | ||
const encodedKey = encoder.encode(key); | ||
const encodedData = encoder.encode(data); | ||
/** | ||
* @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey | ||
*/ | ||
const hmacKey = await crypto.subtle.importKey( | ||
"raw", | ||
encodedKey, | ||
{ | ||
name: "HMAC", | ||
hash: "SHA-256", | ||
}, | ||
true, | ||
["sign", "verify"], | ||
); | ||
/** | ||
* @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign#hmac_2 | ||
*/ | ||
const hmacKey = await crypto.subtle.importKey("raw", encodedKey, { name: "HMAC", hash: "SHA-256" }, true, ["sign"]); | ||
const signature = await crypto.subtle.sign("HMAC", hmacKey, encodedData); | ||
|
||
const hex = bufferToHex(signature); | ||
|
||
return { hex }; | ||
return bufferToHex(signature); | ||
} | ||
|
||
export async function signEmbedUrl(dashboard: string): Promise<string> { | ||
const { EMBED_SECRET, EMBED_CLIENT_ID } = process.env; | ||
if (!EMBED_SECRET || !EMBED_CLIENT_ID) { | ||
throw new Error("SIGMA_EMBED_SECRET is not set"); | ||
if (!SECRET || !CLIENT_ID) { | ||
throw new Error("The Embed `SECRET` or `CLIENT_ID` is missing in the code"); | ||
} | ||
|
||
const searchParamsObject = { | ||
":mode": "userbacked", | ||
":email": "[email protected]", | ||
":external_user_team": "Sales_People", | ||
":account_type": "viewer", | ||
":email": EMAIL, | ||
":external_user_id": EXTERNAL_USER_ID, | ||
":account_type": ACCOUNT_TYPE, | ||
":external_user_team": EXTERNAL_USER_TEAM, | ||
":nonce": uuid(), | ||
":time": `${Math.floor(new Date().getTime() / 1000)}`, | ||
":session_length": "36000", | ||
":client_id": EMBED_CLIENT_ID, | ||
":external_user_id": "123", | ||
":session_length": SESSION_LENGTH, | ||
":client_id": CLIENT_ID, | ||
}; | ||
|
||
const searchParams = new URLSearchParams(searchParamsObject); | ||
|
||
// EMBED_PATH - Generated on your workbook | ||
const urlWithSearchParams = `${dashboard}?${searchParams.toString()}`; | ||
|
||
// EMBED_SECRET - Sigma Embed Secret generated in your admin portal | ||
const SIGNATURE = await simpleHmac({ | ||
key: EMBED_SECRET, | ||
const signature = await simpleHmac({ | ||
key: SECRET, | ||
data: urlWithSearchParams, | ||
}); | ||
|
||
searchParams.append(":signature", SIGNATURE.hex); | ||
searchParams.append(":signature", signature); | ||
|
||
const signedUrl = `${dashboard}?${searchParams.toString()}`; | ||
|
||
return signedUrl; | ||
} | ||
return `${dashboard}?${searchParams.toString()}`; | ||
} |