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

Tried to migrate to Safari but xhr request blocked by CSP #253

Open
BenjaminLiCN opened this issue Apr 24, 2023 · 1 comment
Open

Tried to migrate to Safari but xhr request blocked by CSP #253

BenjaminLiCN opened this issue Apr 24, 2023 · 1 comment

Comments

@BenjaminLiCN
Copy link

BenjaminLiCN commented Apr 24, 2023

Refused to connect to 'https://mycompany.sandbox.my.salesforce.com/services/data/v56.0/query?q=select%20Id%2C%20Name%20FROM%20User%20LIMIT%201&cache=0.22271687033207455' because it violates the following Content Security Policy directive: "connect-src 'self' https://static.lightning.force.com https://api.bluetail.salesforce.com https://staging.bluetail.salesforce.com https://preprod.bluetail.salesforce.com blob: *.vf.force.com https://mycompany.sandbox.file.force.com https://cs171.salesforce.com https://notification-service.sfproxy.null.ia5.aws.sfdc.cl wss://notification-service.sfproxy.null.ia5.aws.sfdc.cl".

So in safari extension I only have one file named script.js which is lilke background.js. It can send data to Swfit code and display them.

let sfConn = {
    async rest(url, {logErrors = true, method = "GET", api = "normal", body = undefined, bodyType = "json", headers = {}, progressHandler = null} = {}) {
        try {
            const sidRegex = /sid=(.*?);/;
            const sidMatch = document.cookie.match(sidRegex);
            const sessionId = sidMatch ? sidMatch[1] : null;
            const hostname = window.location.hostname;
            let xhr = new XMLHttpRequest();
            url += (url.includes("?") ? "&" : "?") + "cache=" + Math.random();
            xhr.open(method, "https://" + hostname + url, true);
            console.log("https://" + hostname + url + " sid: " + sessionId);
            xhr.setRequestHeader("Accept", "application/json; charset=UTF-8");
            if (api == "bulk") {
                xhr.setRequestHeader("X-SFDC-Session", sessionId);
            } else if (api == "normal") {
                xhr.setRequestHeader("Authorization", "Bearer " + sessionId);
            } else {
                throw new Error("Unknown api");
            }
            
            if (body !== undefined) {
                if (bodyType == "json") {
                    body = JSON.stringify(body);
                    xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
                } else if (bodyType == "raw") {
                    // Do nothing
                } else {
                    throw new Error("Unknown bodyType");
                }
            }
            xhr.responseType = "json";
            console.log("before promise");
            await new Promise((resolve, reject) => {
                if (progressHandler) {
                    progressHandler.abort = () => {
                        let err = new Error("The request was aborted.");
                        err.name = "AbortError";
                        reject(err);
                        xhr.abort();
                    };
                }
                
                xhr.onreadystatechange = () => {
                    if (xhr.readyState == 4) {
                        resolve();
                    }
                };
                console.log("sending xhr");
                xhr.send(body);
            });
            if (xhr.status >= 200 && xhr.status < 300) {
                console.log("good, returning ");
                console.log(xhr);
                console.log(xhr.response);
                return xhr.response;
            } else if (xhr.status == 0) {
                if (!logErrors) { console.error("Received no response from Salesforce REST API", xhr); }
                let err = new Error();
                err.name = "SalesforceRestError";
                err.message = "Network error, offline or timeout";
                throw err;
            } else {
                if (!logErrors) { console.error("Received error response from Salesforce REST API", xhr); }
                let err = new Error();
                err.name = "SalesforceRestError";
                err.detail = xhr.response;
                try {
                    err.message = err.detail.map(err => `${err.errorCode}: ${err.message}${err.fields && err.fields.length > 0 ? ` [${err.fields.join(", ")}]` : ""}`).join("\n");
                } catch (ex) {
                    err.message = JSON.stringify(xhr.response);
                }
                if (!err.message) {
                    err.message = "HTTP error " + xhr.status + " " + xhr.statusText;
                }
                throw err;
            }
        } catch(e) {
            console.log(e);
        }
        
    }
};
    const fullQuerySelect = "select Id, Name FROM User LIMIT 1";
    console.log("calling");
    sfConn.rest("/services/data/v56.0" + "/query?q=" + encodeURIComponent(fullQuerySelect), {logErrors: false})
    .then(res => {
      for (let record of res.records) {
        console.log(record.Name);
      }
    }).catch(() => {
      //Swallow this exception since it is likely due to missing standard attributes on the record - i.e. an invalid query.
      console.log("caught error");
    });

This is executed in my sandbox hostname ends with "lightning.force.com", however I observed the request will be redirected to another ends with "my.salesforce.com". I suspect this is why it blocks my request. Anyone can directly copy this code and run in chrome console.

Could anyone shed some light, please?
First image is the successful request sent by inspector extension on chrome.
image

Second is my code executed on chrome console
image

@BenjaminLiCN
Copy link
Author

BenjaminLiCN commented Apr 25, 2023

According to this article, it is because my request is generated from lightning.force.com which is the same as LWC. The api hostname ends with salesforce.com. And since they are not the same origin hence the request fails. What I couldn't understand is why is Inspector capable of making calls from salesforce.com????? I didn't see any secret in the inspector.js code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant