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

Broken chat UI #5409

Open
eelshorbagy opened this issue Jan 20, 2025 · 11 comments
Open

Broken chat UI #5409

eelshorbagy opened this issue Jan 20, 2025 · 11 comments
Labels
Bot Services Required for internal Azure reporting. Do not delete. Do not change color. bug Indicates an unexpected problem or an unintended behavior. customer-reported Required for internal Azure reporting. Do not delete. resolved Indicates that the issue will be closed if no further question arise

Comments

@eelshorbagy
Copy link

Is it an issue related to Adaptive Cards?

No

Is this an accessibility issue?

No

What version of Web Chat are you using?

Latest production

Which distribution are you using Web Chat from?

Bundle (webchat.js)

Which hosting environment does this issue primarily affect?

Web apps

Which browsers and platforms do the issue happened?

Browser: Edge (latest)

Which area does this issue affect?

Customization: Branding

Which theme pack does this issue affect?

I did not test it on other theme packs

What is the public URL for the website?

No response

Please describe the bug

We have a project to integrate a copilot studio agent into our website. I face an issue with the UI CSS is not loading correctly quite often. I am attaching two images for having the chat loaded correctly vs broken one.

Image Image

When I debug in developer tools to see the difference between those two cases, in the correct case I can see the styles of the dialog elements exist and it links to an element in the head similar to this <style data-emotion="webchat--css-frzek" nonce="" data-s=""></style>
In the other case when the UI is broken, the styles of the dialog elements don't exist, although the same element exists in the head <style data-emotion="webchat--css-frzek" nonce="" data-s=""></style>

Do you see any errors in console log?

I see an error, but it exists in both cases where the issue exists and where it doesn't:

webchat.js:2 
 Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-zjjiCy+CluvwpBZ4xo5EGeR/zOVey5prUR/j+I0kT2U=' 'report-sample' 

Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.

Please note that I already sent the nonce to renderWebChat function which eliminated many errors like that, but this one still exists. I assume it's not related to the current issue.

How to reproduce the issue?

Please contact me to send you internal link in Microsoft to access the website.

What do you expect?

Having a correct non-broken UI for the chat dialog every time I refresh the page.

What actually happened?

I am adding more screenshots for the developer tool to compare the case where the UI is correctly working vs the broken UI

Correct:
Image
Image

Broken:
Image
Image

Do you have any screenshots or recordings to repro the issue?

No response

Adaptive Card JSON

Additional context

No response

@eelshorbagy eelshorbagy added Bot Services Required for internal Azure reporting. Do not delete. Do not change color. bug Indicates an unexpected problem or an unintended behavior. customer-reported Required for internal Azure reporting. Do not delete. labels Jan 20, 2025
@OEvgeny
Copy link
Collaborator

OEvgeny commented Jan 20, 2025

Is nonce a static value? There seems to be a race condition or something preventing it from working properly in some cases. May we see how you're instantiating Web Chat?

@eelshorbagy
Copy link
Author

@OEvgeny, the nonce is not a static value. It's changing with every run.

Here is how I instantiate the webchat:

    <div id="webchat" role="main" class="chat-dialog">
        <script nonce="@Model.ApplicationContext.Nonce">
            async function renderChatWidget() {
                const { token } = await fetchJSON(tokenEndpoint);
                const directLine = window.WebChat.createDirectLine({ token });

                const styleOptions = {
                    primaryFont: 'Segoe UI',
                    backgroundColor: '#EDF2F1',
                    bubbleBackground: '#FFF',
                    bubbleBorderRadius: '12px',
                    bubbleFromUserBorderRadius: '12px',
                    bubbleFromUserBackground: '#2169EB',
                    bubbleFromUserTextColor: 'White',
                    sendBoxButtonColor: '#2169EB',
                    hideUploadButton: true,
                    sendBoxTextWrap: true,
                };

                const store = WebChat.createStore(
                    {},
                    ({ dispatch }) => next => action => {
                        const { type } = action;

                        if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
                            const actions = [
                                {
                                    type: "WEB_CHAT/SEND_EVENT",
                                    payload: {
                                        name: "pvaSetContext",
                                        value: {
                                            //send some variables values
                                        }
                                    },
                                },
                                {
                                    type: "DIRECT_LINE/POST_ACTIVITY",
                                    meta: {
                                        method: "keyboard",
                                    },
                                    payload: {
                                        activity: {
                                            channelData: {
                                                postBack: true,
                                            },
                                            name: 'startConversation',
                                            type: "event"
                                        },
                                    },
                                }
                            ];
                            next(action);
                            const results = actions.map(a => store.dispatch(a));
                            return results;
                        }

                        return next(action);
                    });

                window.WebChat.renderWebChat(
                    {
                        directLine: directLine,
                        nonce: '@Model.ApplicationContext.Nonce',
                        store,
                        styleOptions
                    },
                    document.getElementById('webchat')
                );

                document.querySelector('#webchat > *').focus();
            }

            // Render the WebChat when the page loads
            (async () => {
                await renderChatWidget()
            })()
        </script>
    </div>

@eelshorbagy
Copy link
Author

Is there any update here?

@OEvgeny
Copy link
Collaborator

OEvgeny commented Jan 24, 2025

I'm still figuring out steps to repro the behavior you're seeing.

@eelshorbagy
Copy link
Author

@OEvgeny, thank you for your effort!

@OEvgeny
Copy link
Collaborator

OEvgeny commented Jan 27, 2025

Can't reproduce: https://stackblitz.com/edit/sb1-dmhmmphr?file=index.js

You can verify nonce works by commenting out the property. Make sure that nonce doesn't change after Web Chat is initialized as it may affect any styles it needs to add during bootstrap.

I tried 4.17.0, 4.18.0 and both the latest and main tag from npm.

Please let me know if anything from your setup is missing on the repro.

@eelshorbagy
Copy link
Author

I have tried to disable the nonce in our website then I couldn't reproduce. So, it seems that the bug is related to using nonce.

Also, I made sure that the nonce value doesn't change after the WebChat is initialized.

I am not sure what else I should share here to help reproduce but the issue is still persistent.

Image

Here in the above screenshot, these are the CSP errors that I get when the issue is reproduced. When I click on webchat.js to see the code that is causing the issue, I can see two parts as follows

Image Image

Can this help to identify the issue?

@OEvgeny
Copy link
Collaborator

OEvgeny commented Jan 28, 2025

But my repro already includes nonce as well and I'm not able to verify the issue is present on any of the above versions. Sorry to say that, but without repro it is hard to move forward on this. I've put already some time to create a repro, so anyone can access and edit it. Could you please help me to adjust the repro to better reassemble your setup?

@eelshorbagy
Copy link
Author

Hi @OEvgeny , after some trials, I am now able to reproduce using the sample you have added, here is the updated version: https://stackblitz.com/edit/sb1-9xjmqekx?file=index.html .

Actually, the problem happens with some values of the nonce. It seems some special characters are breaking the code somehow. Could you please have a look and let me know your opinion?

@OEvgeny
Copy link
Collaborator

OEvgeny commented Jan 29, 2025

Here is what happens: https://stackblitz.com/edit/sb1-baunno7h?file=index.html,index.js%3AL68

Image

The issue arises because HTML entities like &#x2B; (which represents +) are decoded when the HTML is parsed. When you set the attribute via JavaScript using setAttribute, the value is taken literally without decoding entities, leading to a mismatch.

To fix this, ensure you use the actual + character in both cases instead of the HTML entity &#x2B;:

  1. In HTML: Directly use + without encoding:

    <script nonce="YaNcMQ1em5KyhXQVZvBbVPPDVj84O3e9PsWS7mM+OSk=">
  2. In JavaScript: Pass the + directly:

    element.setAttribute('nonce', 'YaNcMQ1em5KyhXQVZvBbVPPDVj84O3e9PsWS7mM+OSk=');

Why this works: Browsers decode HTML entities in attributes during parsing. By using the literal + (not &#x2B;), you ensure consistency between HTML and JavaScript-set values. Nonces typically include Base64 characters (A-Za-z0-9+/=), and + is safe in quoted HTML attributes.

Alternatively you can pass the value without html entities escaped only to JS, as the demo shows, but this is not recommended.

@OEvgeny OEvgeny added resolved Indicates that the issue will be closed if no further question arise and removed needs-author-feedback labels Jan 29, 2025
@eelshorbagy
Copy link
Author

Thank you @OEvgeny this solved the issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bot Services Required for internal Azure reporting. Do not delete. Do not change color. bug Indicates an unexpected problem or an unintended behavior. customer-reported Required for internal Azure reporting. Do not delete. resolved Indicates that the issue will be closed if no further question arise
Projects
None yet
Development

No branches or pull requests

2 participants