From 15fbd4e19395b2729f0c770036e7e27eced945e5 Mon Sep 17 00:00:00 2001 From: baljesingh Date: Wed, 20 Nov 2024 23:58:33 -0800 Subject: [PATCH 1/4] Add Nested App Auth API sections to the Teams test app --- .../src/components/NestedAppAuthAPIs.tsx | 157 +++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) diff --git a/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx b/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx index 35173047a0..4b8edad58b 100644 --- a/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx +++ b/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx @@ -1,9 +1,27 @@ import { nestedAppAuth } from '@microsoft/teams-js'; -import React, { ReactElement } from 'react'; +import React, { ReactElement, useState } from 'react'; -import { ApiWithoutInput } from './utils'; +import { ApiWithoutInput, ApiWithTextInput } from './utils'; import { ModuleWrapper } from './utils/ModuleWrapper'; +const NestedAppAuthRequest = JSON.stringify({ + messageType: 'NestedAppAuthRequest', + method: 'GetToken', + sendTime: 1732269811006, + clientLibrary: 'MetaOS', + clientLibraryVersion: '1.0.0', + requestId: '684352c2-7ab7-4def-b7e1-56a386c02a0a', + tokenParams: { + correlationId: '39dc85fe-9054-11ed-a1eb-0242ac120002', + }, +}); + +type NestedAppAuthBridge = { + postMessage: (message: string) => void; + addEventListener: (type: string, listener: (response: unknown) => void) => void; + removeEventListener: (type: string, listener: (response: unknown) => void) => void; +}; + const NestedAppAuthAPIs = (): ReactElement => { const CheckIsNAAChannelRecommended = (): ReactElement => ApiWithoutInput({ @@ -12,9 +30,144 @@ const NestedAppAuthAPIs = (): ReactElement => { onClick: async () => `NAA channel ${nestedAppAuth.isNAAChannelRecommended() ? 'is' : 'is not'} recommended`, }); + const SendMessageToNestedAppAuthBridge = (): React.ReactElement => + ApiWithTextInput({ + name: 'SendMessageToNestedAppAuthBridge', + title: 'Send NAA Message to NestedAppAuth Bridge', + onClick: { + validateInput: () => {}, + submit: async (input, setResult) => { + const bridge = (window as Window & { nestedAppAuthBridge?: NestedAppAuthBridge }).nestedAppAuthBridge; + if (!bridge) { + setResult('Bridge not available'); + return 'Bridge not available'; + } + + // Define listener for responses + const listener = (response: unknown): void => { + setResult(JSON.stringify(response, null, 2)); + bridge.removeEventListener?.('message', listener); + }; + + // Add event listener + bridge.addEventListener?.('message', listener); + bridge.postMessage?.(JSON.stringify(input)); + + setResult('Message sent successfully, awaiting response...'); + return 'Message sent successfully'; + }, + }, + defaultInput: NestedAppAuthRequest, + }); + + const SendMessageToTopWindow = (): React.ReactElement => + ApiWithTextInput({ + name: 'SendMessageToTopWindow', + title: 'Send NAA Message to Top Window', + onClick: { + validateInput: () => {}, + submit: async (input, setResult) => { + try { + const targetOrigin = 'https://local.teams.office.com:8080'; + + // Check if window.top is accessible + if (!window.top) { + setResult('Top window not accessible'); + return 'Top window not accessible'; + } + + // Define listener for responses + const listener = (event: MessageEvent): void => { + // Ensure the message comes from the expected origin + if (event.origin !== targetOrigin) { + console.warn('Received message from an unexpected origin:', event.origin); + return; + } + + console.log('Received response from top window:', event.data); + setResult(JSON.stringify(event.data, null, 2)); // Pretty-print response + window.removeEventListener('message', listener); + }; + + // Add event listener for messages + window.addEventListener('message', listener); + window.top.postMessage(input, targetOrigin); + + setResult('Message sent to top window, awaiting response...'); + return 'Message sent to top window'; + } catch (error) { + console.error('Error sending message to top window:', error); + setResult(`Error: ${error}`); + return `Error: ${error}`; + } + }, + }, + defaultInput: JSON.stringify({ + id: '2', + func: 'nestedAppAuth.execute', + args: [], + data: NestedAppAuthRequest, + }), + }); + + const AddChildIframeSection = (): React.ReactElement | null => { + const [iframeAdded, setIframeAdded] = useState(false); + + const addChildIframe = (): void => { + if (iframeAdded) { + console.log('Iframe already added.'); + return; + } + + const iframeContainer = document.getElementById('NestedChildiframeContainer'); + if (!iframeContainer) { + console.error('Container not found: NestedChildiframeContainer'); + return; + } + + const childIframe = document.createElement('iframe'); + childIframe.src = `${window.location.href}?appInitializationTest=true&groupedMode=NestedAppAuthAPIs`; + childIframe.id = 'nestedAuthChildIframe'; + childIframe.width = '100%'; + childIframe.height = '400px'; + childIframe.style.border = 'none'; + + iframeContainer.appendChild(childIframe); + setIframeAdded(true); + }; + + return ( +
+

Add Nested Child Iframe

+ +
+
+ ); + }; + return ( + + + ); }; From 46e58c441f09f990be8ed2a078fd2b83ec78a92c Mon Sep 17 00:00:00 2001 From: baljesingh Date: Mon, 25 Nov 2024 11:02:16 -0800 Subject: [PATCH 2/4] Update NestedAppAuthAPIs.tsx --- apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx b/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx index 4b8edad58b..b3fb2a9b4c 100644 --- a/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx +++ b/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx @@ -8,11 +8,11 @@ const NestedAppAuthRequest = JSON.stringify({ messageType: 'NestedAppAuthRequest', method: 'GetToken', sendTime: 1732269811006, - clientLibrary: 'MetaOS', + clientLibrary: 'testOS', clientLibraryVersion: '1.0.0', - requestId: '684352c2-7ab7-4def-b7e1-56a386c02a0a', + requestId: '684352c2-7ab7-4def-b7e1-XXXXXXXXXXX', tokenParams: { - correlationId: '39dc85fe-9054-11ed-a1eb-0242ac120002', + correlationId: '39dc85fe-9054-11ed-a1eb-XXXXXXXXXXX', }, }); From 8011dd3b352f70f7f219335ed8d82970f2f38157 Mon Sep 17 00:00:00 2001 From: baljesingh Date: Mon, 25 Nov 2024 14:24:54 -0800 Subject: [PATCH 3/4] Add input validator --- .../src/components/NestedAppAuthAPIs.tsx | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx b/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx index b3fb2a9b4c..a9c37b63fd 100644 --- a/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx +++ b/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx @@ -16,6 +16,48 @@ const NestedAppAuthRequest = JSON.stringify({ }, }); +const validateNAARequestInput = (input): void => { + if (!input) { + throw new Error('Input is required.'); + } + + if (input.messageType !== 'NestedAppAuthRequest') { + throw new Error('Invalid or missing messageType. Expected "NestedAppAuthRequest".'); + } + + if (!input.method) { + throw new Error('Method name is required in payload'); + } + + if (!input.requestId) { + throw new Error('RequestId is required in payload'); + } +}; + +const validateTopWindowNAARequestInput = (input): void => { + if (!input) { + throw new Error('Input is required.'); + } + + if (!input.id) { + throw new Error('"id" is required.'); + } + + if (!input.func) { + throw new Error('"func" is required.'); + } + + if (!input.data) { + throw new Error('"data" is required with NAA payload'); + } + + try { + validateNAARequestInput(JSON.parse(input.data)); + } catch (error) { + throw new Error('NAA payload must be a valid JSON'); + } +}; + type NestedAppAuthBridge = { postMessage: (message: string) => void; addEventListener: (type: string, listener: (response: unknown) => void) => void; @@ -35,7 +77,7 @@ const NestedAppAuthAPIs = (): ReactElement => { name: 'SendMessageToNestedAppAuthBridge', title: 'Send NAA Message to NestedAppAuth Bridge', onClick: { - validateInput: () => {}, + validateInput: validateNAARequestInput, submit: async (input, setResult) => { const bridge = (window as Window & { nestedAppAuthBridge?: NestedAppAuthBridge }).nestedAppAuthBridge; if (!bridge) { @@ -65,7 +107,7 @@ const NestedAppAuthAPIs = (): ReactElement => { name: 'SendMessageToTopWindow', title: 'Send NAA Message to Top Window', onClick: { - validateInput: () => {}, + validateInput: validateTopWindowNAARequestInput, submit: async (input, setResult) => { try { const targetOrigin = 'https://local.teams.office.com:8080'; @@ -119,9 +161,9 @@ const NestedAppAuthAPIs = (): ReactElement => { return; } - const iframeContainer = document.getElementById('NestedChildiframeContainer'); + const iframeContainer = document.getElementById('nestedChildiframeContainer'); if (!iframeContainer) { - console.error('Container not found: NestedChildiframeContainer'); + console.error('Container not found: nestedChildiframeContainer'); return; } @@ -147,7 +189,7 @@ const NestedAppAuthAPIs = (): ReactElement => { disabled={iframeAdded} />
Date: Mon, 25 Nov 2024 21:49:17 -0800 Subject: [PATCH 4/4] Update the casing of the variables --- .../src/components/NestedAppAuthAPIs.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx b/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx index a9c37b63fd..60c594165f 100644 --- a/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx +++ b/apps/teams-test-app/src/components/NestedAppAuthAPIs.tsx @@ -74,7 +74,7 @@ const NestedAppAuthAPIs = (): ReactElement => { const SendMessageToNestedAppAuthBridge = (): React.ReactElement => ApiWithTextInput({ - name: 'SendMessageToNestedAppAuthBridge', + name: 'sendMessageToNestedAppAuthBridge', title: 'Send NAA Message to NestedAppAuth Bridge', onClick: { validateInput: validateNAARequestInput, @@ -104,7 +104,7 @@ const NestedAppAuthAPIs = (): ReactElement => { const SendMessageToTopWindow = (): React.ReactElement => ApiWithTextInput({ - name: 'SendMessageToTopWindow', + name: 'sendMessageToTopWindow', title: 'Send NAA Message to Top Window', onClick: { validateInput: validateTopWindowNAARequestInput, @@ -161,9 +161,9 @@ const NestedAppAuthAPIs = (): ReactElement => { return; } - const iframeContainer = document.getElementById('nestedChildiframeContainer'); + const iframeContainer = document.getElementById('nestedChildIframeContainer'); if (!iframeContainer) { - console.error('Container not found: nestedChildiframeContainer'); + console.error('Container not found: nestedChildIframeContainer'); return; } @@ -189,7 +189,7 @@ const NestedAppAuthAPIs = (): ReactElement => { disabled={iframeAdded} />