Closed umrashrf closed 7 months ago
Hi @umrashrf, the enterprise.js is for reCAPTCHA enterprise. The script will only load if you use reCAPTCHA enterprise. Can you give more information about the violation?
We also have reCAPTCHA v2 script in https://github.com/firebase/firebase-js-sdk/blob/98cfcbd0c0629d4aee60f686edc0da3e27ce36c6/packages/auth/src/platform_browser/recaptcha/recaptcha_loader.ts#L33, does this cause an issue too?
They have been there for a long time already.
@NhienLam
I have a similar complaint from Google saying that my extension violates the program policy.
Violation reference ID: Blue Argon
Violation: Including remotely hosted code in a Manifest V3 item.
After some investigation, it seems that there's a _loadJS
function that creates a script tag and loads code from a remote URL.
Then in gapi.ts, the function is called to load from an external API (which is the Google API).
Could you please have a look and help us do something to solve the issue?
Thank you.
I also received a rejection notification today. Several of my extensions rely on Firebase's auth, and now they can't be updated.
I think this is related to the push to Manifest V3 which will be required of all Chrome web store apps as of Jan 2024. Specifically this prohibition against remotely hosted files: https://developer.chrome.com/docs/extensions/mv3/intro/mv3-overview/#remotely-hosted-code
The Chrome Web Store team has officially confirmed that the error is caused by the _loadJS
function responsible for loading the Google API.
Here's what they say:
We would like to let you know that under static/js/background.js and static/js/content-script.js files there is an external js file (https://apis.google.com/js/api.js?onload=${t}) that was injected which is against our Chrome Web Store policies.
Please remove the external code file(js file) or else include that external js file in the extension’s code package and re-submit your extension for a review. Your submission will be approved if we find it to be compliant with all our policies.
Looks like something has to change to solve this issue.
I will add, it looks like that enterprise.js is needed for reCaptcha as part of the signInWithPhoneNumber
function. In my app, I am not using that function or that way of signing in at all. The problem is that all sign-in functions are in the same file/class in the firebase sdk.
enterprise
@NhienLam I am not using enterprise. I am using npm install firebase
and that's it.
I see there is some discussion about it in this email thread as well
Can folks try if the solution posted in that thread works? That thread shows the implementation with the non-modular SDK which is not tree-shakeable. With the modular SDK, the recaptcha script loader could get tree-shaken if unused.
Can you try something like this:
import { GoogleAuthProvider, initializeAuth } from "firebase/auth";
chrome.identity.getAuthToken({ 'interactive': true }, async (token) => {
const credential = GoogleAuthProvider.credential(null, token);
try {
const app = initializeApp({/** Your app config */});
const auth = initializeAuth(app, {popupRedirectResolver: undefined, persistence: indexDBLocalPersistence});
const {user} = await auth.signInWithCredential(credential)
console.log(`the user object is here! - ${user}`)
} catch (e) {
console.error(error);
}
});
Please use SDK version 9.19.0 or older.
Also, in addition, can folks answer the following questions: 1) Are you using the modular or compat SDK? 2) Which auth methods are you using in the extension code? Thanks!
@prameshj My extensions package.json contains type: "module"
package.json
"dependencies": {
"firebase": "^10.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vite-plugin-css-injected-by-js": "^3.1.1",
"webextension-polyfill": "^0.10.0"
},
$ grep -E 'node_modules/.*compat.*' package-lock.json
"node_modules/@babel/compat-data": {
"node_modules/@firebase/analytics-compat": {
"node_modules/@firebase/analytics-compat/node_modules/tslib": {
"node_modules/@firebase/app-check-compat": {
"node_modules/@firebase/app-check-compat/node_modules/tslib": {
"node_modules/@firebase/app-compat": {
"node_modules/@firebase/app-compat/node_modules/tslib": {
"node_modules/@firebase/auth-compat": {
"node_modules/@firebase/auth-compat/node_modules/tslib": {
"node_modules/@firebase/database-compat": {
"node_modules/@firebase/database-compat/node_modules/tslib": {
"node_modules/@firebase/firestore-compat": {
"node_modules/@firebase/firestore-compat/node_modules/tslib": {
"node_modules/@firebase/functions-compat": {
"node_modules/@firebase/functions-compat/node_modules/tslib": {
"node_modules/@firebase/installations-compat": {
"node_modules/@firebase/installations-compat/node_modules/tslib": {
"node_modules/@firebase/messaging-compat": {
"node_modules/@firebase/messaging-compat/node_modules/tslib": {
"node_modules/@firebase/performance-compat": {
"node_modules/@firebase/performance-compat/node_modules/tslib": {
"node_modules/@firebase/remote-config-compat": {
"node_modules/@firebase/remote-config-compat/node_modules/tslib": {
"node_modules/@firebase/storage-compat": {
"node_modules/@firebase/storage-compat/node_modules/tslib": {
"node_modules/core-js-compat": {
Thanks.. it would be great if folks can confirm:
1) if the workaround above helps? 2) What auth providers are you using in extensions? 3) Are you using the modular web SDK?
We encountered a similar issue. According to the requirements outlined by the Google Chrome Extension team (found at https://developer.chrome.com/docs/webstore/program-policies/mv3-requirements/), we are prohibited from utilizing files hosted on a third-party server or CDN. All files must be stored locally. Could you please create a version where these files are stored locally?
Here are the links to the images we need to use:
I have a similar issue and tried the workaround suggested by @prameshj, but it did not work. To temporarily solve the problem, I added post build script to replace _loadJS
function content with an empty promise. It can cover most cases, but in some cases, the logic can be breached. As I use vite
with rollup
, I configure the post-build script in this way (you can use this regex to implement your own post-build script):
import modify from 'rollup-plugin-modify';
//...
rollupOptions: {
plugins: [
modify({
find: /function\s*\w*\s*_loadJS\([\w\s,]*\)\s*{([\w\W]*?)}$/gim,
replace: 'function _loadJS() { return Promise.resolve(); };',
}),
]
}
Same issue here.
Also, in addition, can folks answer the following questions: 1) Are you using the modular or compat SDK? 2) Which auth methods are you using in the extension code? Thanks!
1) Using modular SDK 2) getAuth, onAuthStateChanged, signInWithCustomToken, signOut, signInWithCredential, getAdditionalUserInfo
Workaround doesn't help. We don't use chrome.identity.getAuthToken
.; instead authenticating the user on our website, creating/sending custom token to the extension where we authenticate the user then with signInWithCustomToken
.
I have the same problem, I tried a lot. I have implemented Google Authentication via the popup, but again I get "Breach Link ID: Blue Argon". Code for Google auth.
auth.ts
import {
GoogleAuthProvider,
OAuthCredential,
signInWithCredential,
} from "firebase/auth";
import { storage } from "webextension-polyfill";
const getGoogleAccessToken = async (prompt?: boolean): Promise<string> => {
const { accessToken } = await storage.local.get("accessToken");
if (accessToken) {
return accessToken;
}
if (prompt === false) return "";
return new Promise((resolve) => {
chrome.identity.getAuthToken({ interactive: true }, token =>
{
if (chrome.runtime.lastError || ! token) {
console.log(chrome.runtime.lastError);
return
}
resolve(token);
})
});
};
const getGoogleAuthCredential = async (
prompt?: boolean
): Promise<OAuthCredential | null> => {
const accessToken = await getGoogleAccessToken(prompt);
await storage.local.set({ accessToken });
const credential = GoogleAuthProvider.credential(null, accessToken);
return credential;
};
const logIn = async (prompt?: boolean) => {
try {
const credential = await getGoogleAuthCredential(prompt);
const result = await signInWithCredential(auth, credential);
return result.user;
} catch (e) {
console.error(e);
storage.local.remove("accessToken");
return null;
}
};
manifest.json
"background": {
"service_worker": "auth.ts",
"type": "module"
},
"permissions": ["storage", "tabs", "identity"],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; script-src-elem 'self' 'unsafe-inline';"
},
"oauth2": {
"client_id": "CLIENT_ID",
"scopes": [
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"
]
},
Thanks for trying it out, @khlevon @Georg7 @XchHarutyunyan
Can you confirm if you are using firebase SDK version 9.19.0 or older? Also, can you share more details on what the error was, when using the workaround? Was it the same remote code security violation or a different issue?
Can you confirm if you are using firebase SDK version 9.19.0 or older?
"firebase": "^10.4.0"
Also, can you share more details on what the error was, when using the workaround? Was it the same remote code security violation or a different issue?
We don't use chrome.identity.getAuthToken
so the workaround is not a viable solution for us. There is also no definite way without resubmitting the extension. However, the initial policy violation email states that if "...if the new draft fails to comply with our policies, both the draft and the existing store listing will be removed."
We can't risk our extension being taken down but we also urgently need to update the extension.
Can you confirm if you are using firebase SDK version 9.19.0 or older?
"firebase": "^10.4.0"
Can you try your same extension code with 9.19.0 instead?
Also, can you share more details on what the error was, when using the workaround? Was it the same remote code security violation or a different issue?
We don't use
chrome.identity.getAuthToken
so the workaround is not a viable solution for us. There is also no definite way without resubmitting the extension. However, the initial policy violation email states that if "...if the new draft fails to comply with our policies, both the draft and the existing store listing will be removed."We can't risk our extension being taken down but we also urgently need to update the extension.
Can you confirm if you are using firebase SDK version 9.19.0 or older?
"firebase": "^10.4.0"
Can you try your same extension code with 9.19.0 instead?
Also, can you share more details on what the error was, when using the workaround? Was it the same remote code security violation or a different issue?
We don't use
chrome.identity.getAuthToken
so the workaround is not a viable solution for us. There is also no definite way without resubmitting the extension. However, the initial policy violation email states that if "...if the new draft fails to comply with our policies, both the draft and the existing store listing will be removed." We can't risk our extension being taken down but we also urgently need to update the extension.
To clarify, @prameshj , resubmit the extension without the workaround (as it's not applicable to us) with 9.19.0? If so, and if the review fails, how can we avoid our extension being taken down?
9.19.0 also calls https://apis.google.com/js/api.js?onload=${t}
in the function called jn
(which appears to be _loadJS
in later versions)
Thanks for trying it out, @khlevon @Georg7 @XchHarutyunyan
Can you confirm if you are using firebase SDK version 9.19.0 or older? Also, can you share more details on what the error was, when using the workaround? Was it the same remote code security violation or a different issue?
I'm using "firebase": "^9.9.2", Remote code security violation error. Above I have shared my code.
I'm not sure if this is relevant to this discussion but have you tried using the replace-in-file-webpack-plugin
package to remove the https://apis.google.com/js/api.js?onload=${t}
string? This worked for my project.
https://groups.google.com/a/chromium.org/g/chromium-extensions/c/xQmZLc8cu6Q/m/K29jlJIoBQAJ
new ReplaceInFileWebpackPlugin([{
dir: 'build', // replace with your output dir
test: [/background.bundle.js(\.map)?$/], // replace this with something that matches your output
rules: [{
search: 'https://apis.google.com/js/api.js',
replace: '',
}],
}]),
@kazuki-sf Not everyone relies on webpack; instead, many prefer alternative build tools. This current approach is less than ideal. From our perspective, we have also removed these lines of code. I kindly urge the Firebase team to consider using local files instead of remote ones. For those working on Chrome extensions, this issue is particularly critical, as it causes build failures due to these violations.
We're in the same situation. The Google Chrome Extension team says we can't have files on external servers or CDNs. They have to be stored locally. Could you make a version without these files? Without this we couldn't get approval from Chrome Store.
We're facing same issue with our latest version. Chrome Web Store Team complains about remote code policy in our source code, which comes from Firebase. Referring to the:
https://apis.google.com/js/api.js?onload=${t}
https://google.com/recaptcha/enterprise.js
Would be a solution to have a Firebase version which bundles everything in one place avoiding remote code executions.
We're facing same issue with our latest version. Chrome Web Store Team complains about remote code policy in our source code, which comes from Firebase. Referring to the:
https://apis.google.com/js/api.js?onload=${t}
https://google.com/recaptcha/enterprise.js
Would be a solution to have a Firebase version which bundles everything in one place avoiding remote code executions.
@osadchiynikita Did the Chrome Webstore Team confirm these 2 URLs being the issue? I'm only getting boilerplate answers from them. Also, did you get your extension approved after removing these 2 URLs?
Edit: I removed both URLs from the SDK and still got my extension rejected.
Hi folks, Im from the Chrome Extensions team. Really sorry for anyone having problems with this. We are working on the fastest way to unblock yall. in the mean time, I wanted to clear up a few things throughout this thread
chrome.identity.getAuthToken does work for firebase. Here is a slightly larger example - you can git clone the gist url if you want to quickly try it out. The key thing is that it uses a build step (in this case rollup, but webpack or any other modern build works as well) to tree shake. This removes the references to code that could cause it to be flagged in review for remote code. The resulting token from getAuthToken
works the same as the normally get through other firebase auth flows. The most notable issue would be that it is explicitly only for the accounts that are available using the client_id
provided in the oauth2
section of your manifest.json. If you want to support multiple types of accounts, you could also look at launchWebAuthFlow. This will give you a oauth token (via a code
parameter provided on the redirect URI) that you can exchange with the oauth provider for an access token. Neither of these methods have remote code, so they would never cause an issue there.
we are prohibited from utilizing files hosted on a third-party server or CDN. All files must be stored locally. @leonidkuznetsov18
This is 99.99% true. You are not allowed to have a remotely hosted code loaded in your extension. however, there is a bit of an escape hatch. With offscreenDocument, you can load content via an iframe. This is convoluted, but works. Here a demo of what I mean.
It is not clear to me what specifically did not work. If you could elaborate, that would be really helpful for both the Chrome and Firebase teams.
Can you share the verison of firebase you are using (or your package.json)? All of mine tree shake _loadJS away.
Which issue? Your extension being rejected during review, or the workaround not being tree-shaken?
> Workaround doesn't help. We don't use chrome.identity.getAuthToken.;
I understand that you don't, is there a reason you can't?
[>instead authenticating the user on our website, creating/sending custom token to the extension where we authenticate the user then with signInWithCustomToken.]
If it is an oauth/2 flow, it should work without a problem with getAuthToken
. However, it would also work with launchWebAuthFlow
.
what is your extension id?
the checks should not be particularly rigorous. Grepping the compiled output to for _loadJS, or "https://" and seeing if there are any urls would do just fine. I am happy to look over a build if you would like.
Nothing would change if you resubmit with the different version without changing what you are doing. If you share your extension ID I can investigate a bit, but the only reason an existing listing should be being taken down would be if it was also in violation.
> I'm using "firebase": "^9.9.2"
Thank you for sharing the range - would you be able to share the specific version being used? It would be in your package-lock.json, or just by looking at node_modules/firebase/package.json. ^9.9.2 could be anywhere from version 9.9.2 to 9.23.0.
Appreciate the suggestion! But the code should either be being tree shaken out, or it is still being used (at least rollup thinks its still being used, and not removing it) and this would break any usecase that would be expecting that code to be there. Worth noting that your current version doens't capture recaptcha. I really would not recommend doing this, as it is brittle and potentially giving a false sense of security (thinking you removed remote code, but it missing other things). Instead I would highly suggest focusing on either updating to a treeshakeable version of firebase, using a version of auth that didn't use the remote code, or at the very least replace it with a fetch or analytics call so you were aware that it something is breaking in production.
Thanks @patrickkettner for the detailed response!
Which issue? Your extension being rejected during review, or the workaround not being tree-shaken?
Extension being rejected.
I understand that you don't, is there a reason you can't?
We allow Google, Apple, Email/Pwd and keeping users auth from extension and our website in synch. Our current implementation seems to be the most robust and easiest solution.
what is your extension id?
bbfhmkgmbapfpfaoebngcdpneoldnbem
Would be amazing if you could have a look at the extension and point us in the right direction.
Current status: Rejected twice after removing both URLs (previously discussed) from the SDK (v 9.19.0).
@Georg7 I would be happy to, could you answer the other questions I asked you?
@patrickkettner Which answer is missing? I thought I addressed all of them.
Apologies, I conflated some questions with another user.
Looking at the code that is live in the store, are you not using a build step? As mentioned in the first section, the code listed works by tree shaking. That would happen during a build process. The structure of your code and the commented out sections looks like just the raw files are being copied into the directory.
Looking at your background file, you are loading ¹, getAuth
onAuthStateChanged
, signInWithCustomToken
, and signOut
from firebase/auth. None of those would include the apis that are still present (they would haev been removed during the tree shaking step).
I would really recommend using a tool like rollup (here is firebase's guide to this). It works great! and will automagically take care of all of that for you. The gist I linked in my earlier comment shows an example of it as well.
As for how you can avoid the issue with your next submission, all of your rejections were because you there is a reference to a remote URL in your code. You can look at either the build process (if you start using one) or the firebase/firebase-auth.js
file in your submitted extension. if you can find the string "https://apis.google.com/js/api.js", then you still have a problem.
@patrickkettner node_modules/firebase/package.json says "version": "9.9.2"
Thanks @patrickkettner for the taking a looking and giving advice. We're now using Webpack and inspected/searched the build process for said URL and it's no longer present. I've resubmitted the extension again - will update on the outcome.
new ReplaceInFileWebpackPlugin([{ dir: 'build', // replace with your output dir test: [/background.bundle.js(.map)?$/], // replace this with something that matches your output rules: [{ search: 'https://apis.google.com/js/api.js', replace: '', }], }]),
Is it safe to do this?
@rendomnet not recommended
My imports:
import { initializeApp } from "firebase/app";
import { getAuth, onAuthStateChanged, signInWithCustomToken } from "firebase/auth";
import { getFirestore, addDoc, collection, getDocs, Timestamp, query, where } from "firebase/firestore";
import { getDatabase, ref, onChildAdded, remove, off } from "firebase/database";
import { getFunctions, httpsCallable } from "firebase/functions";
When I inspect the build, the function which calls https://apis.google.com/js/api.js
is still being included.
@Georg7 would you be willing to share the code with me? feel free to contact me at patrickkettner@google.com if youd prefer.
@XchHarutyunyan using the same minimal code from the gist I linked in my original comment with 9.9.2, the remote code is being removed during tree shaking. Can you share your code and/or extension id?
With the version of firebase that is live as of writing this, the use of getAuth
will cause the remote code to be included. Rather than use getAuth
in your code, you can use const auth = initializeAuth(app, {popupRedirectResolver: undefined})
like the code used in the workaround @prameshj shared.
With the version of firebase that is live as of writing this, the use of
getAuth
will cause the remote code to be included. Rather than usegetAuth
in your code, you can useconst auth = initializeAuth(app, {popupRedirectResolver: undefined})
like the code used in the workaround @prameshj shared.
This will still include "https://www.google.com/recaptcha/enterprise.js" And also it will sign out after some time....
@XchHarutyunyan using the same minimal code from the gist I linked in my original comment with 9.9.2, the remote code is being removed during tree shaking. Can you share your code and/or extension id?
https://apis.google.com/js/api.js?onload=${t} https://google.com/recaptcha/enterprise.js
I removed these 2 links from my code and Google accepted my build without errors.
Above I have shared my code.
@XchHarutyunyan using the same minimal code from the gist I linked in my original comment with 9.9.2, the remote code is being removed during tree shaking. Can you share your code and/or extension id?
https://apis.google.com/js/api.js?onload=${t} https://google.com/recaptcha/enterprise.js
I removed these 2 links from my code and Google accepted my build without errors.
Above I have shared my code.
Did you literally just delete the links from the build file?
This will still include "https://www.google.com/recaptcha/enterprise.js" And also it will sign out after some time....
@rendomnet I can't speak to anything signing out, however I just checked again to confirm, and enterprise.js
is not included with the workaround after treeshaking has been applied. If you are seeing it included, we would need to dig into your specific build to see why.
@XchHarutyunyan I meant the entire project, rather than the portion you shared (e.g. package.json, etc)
@XchHarutyunyan using the same minimal code from the gist I linked in my original comment with 9.9.2, the remote code is being removed during tree shaking. Can you share your code and/or extension id?
https://apis.google.com/js/api.js?onload=${t} https://google.com/recaptcha/enterprise.js I removed these 2 links from my code and Google accepted my build without errors. Above I have shared my code.
Did you literally just delete the links from the build file?
Yes
I submitted a build with with @prameshj suggestion. Got approved but as @rendomnet mentioned the auth state doesn't seem to persist and the user is logged out after some time.
I went back to using getAuth
and manually removing https://apis.google.com/js/api.js?onload=${t}
https://google.com/recaptcha/enterprise.js
like so:
new ReplaceInFileWebpackPlugin([
{
dir: "dist",
test: [/background.bundle.js(\.map)?$/],
rules: [
{
search: "https://www.google.com/recaptcha/enterprise.js",
replace: "",
},
],
},
]),
Thanks @patrickkettner, I found a temporary solution and I think firebase should update its code to prevent such errors.
@XchHarutyunyan agreed, just trying to help folks in the meantime
Here is my temporary solution, I have added documentation there on how to solve the problem.
@XchHarutyunyan https://github.com/firebase/firebase-js-sdk/issues/7617#issuecomment-1744633177 It's worked for me! Thanks!! And I hope it will be fixed up soon 🙏
@XchHarutyunyan #7617 (comment) It's worked for me! Thanks!! And I hope it will be fixed up soon 🙏
Hi, Can you tell me your version of firebase, or let me take a look at the contents of package.json. I tried to solve it this way but it didn't work. Thank you.
@XchHarutyunyan #7617 (comment) It's worked for me! Thanks!! And I hope it will be fixed up soon 🙏
Hi, Can you tell me your version of firebase, or let me take a look at the contents of package.json. I tried to solve it this way but it didn't work. Thank you.
After adding my changes your package.json should look like this:
{
"private": true,
"scripts": {
...
"postinstall": "patch-package",
...
},
"browserslist": [
...
],
"dependencies": {
...
"firebase": "^9.9.2",
"patch-package": "^8.0.0",
...
},
"devDependencies": {
...
},
"webExt": {
...
},
}
Operating System
macOS Ventura 13.5
Browser Version
116.0.5845.179 (Official Build) (arm64)
Firebase SDK Version
^10.1.0
Firebase SDK Product:
Auth
Describe your project's tooling
I am using this https://github.com/JohnBra/vite-web-extension
Describe the problem
Following code after the build generates minified files containing URLs with enterprise.js so the Chrome Web Store Team complains of a violation.
Steps and code to reproduce issue
Defined in the problem.