Logon to a remote system via a Chrome extension - javascript

This is my first extension and I suspect the way I've gone about structuring the order of calling code is not completely right. I would appreciate pointers please - hopefully I'm fairly close as it has taken weeks of study, trial and error to get this far :-) XMLHttpRequest does not seem to call the system and the extension crashes a lot.
In the popup.html, there's a SignIn button which opens the 'popup' form signin.html via a listener in background.js. The signin page contains a form with a username & password inputs, and a signin button. Clicking this button calls signin.js to pickup the data from the form, and calls a routine in background.js to connect to the system (could this be the issue - since this was all kicked off from the background.js in the first place???)
In the code,e I'm connecting to Google so I know I have a website that works - I'll deal with the logon part later. Thanks.
manifest.json:
{
"name": "logon test",
"description": "logon test",
"version": "1.0",
"manifest_version": 2,
"icons": { "128": "images/logon.png" },
"browser_action": {
"default_icon": "images/logon.png",
"default_title": "logon test",
"default_popup": "popup.html" },
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"background",
"storage",
"activeTab",
"nativeMessaging",
"http://www.google.com/*",
"https://www.google.com/*"
]
}
popup.html:
<html>
<head>
<script type="text/javascript" src="popup.js"></script>
</head>
<body>
<button id = "signin">Sign In</button>
</body>
</html>
popup.js:
function onSignIn() {
chrome.extension.sendMessage({'action' : 'signin', 'url' :
'/signin.html'});
} //onSignIn
document.getElementById('signin').addEventListener('click', onSignIn);
**signin.html:**
<html>
<body>
<form>
<input name="userid" type="text" id="userid" value="User ID">
<input name="password" type="password" id="password">
<input type="submit" name="submit" id="submit" value="Login">
</form>
<script src="signin.js"></script>
</body>
</html>
signin.js:
document.forms[0].onsubmit = function(e) {
e.preventDefault(); // Prevent submission
var password = document.getElementById('password').value;
var userid = document.getElementById('userid').value;
chrome.runtime.getBackgroundPage(function(bgWindow) {
bgWindow.signIn(password, userid); //background page
window.close(); // Close dialog
});
};
background.js:
function signIn(inPass, inUserid) { //called from signin.html popup
var xhr = new XMLHttpRequest();
if (xhr === null){
alert("Unable to create request");
} else {
xhr.open('GET', 'http://www.google.com/search?q=helloworld',
true);
xhr.onreadystatechange = function() {
var resp = JSON.parse(this.responseText);
alert("result here" + resp);
} //readystate
};
}
xhr.send(null);
} //signin
// button functionality - called from popup.html
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
{
if (request.action === 'signin') {
chrome.tabs.create({
url: chrome.extension.getURL(request.url),
active: false
}, function(tab) {
chrome.windows.create({
tabId: tab.id,
type: 'popup',
focused: true,
left: 500,
top: 20,
width: 450,
height: 200});
}); //tab
} //if
return true;
});

Related

Chrome Extension: Fetching the value of a DOM element

I'm building my first Chrome extension and my goal is to fetch the value of a DOM element from the extension popup by the click of a button. I'm basically following the exact documentation on how to send a message but keep getting:
'Error: Could not establish connection. Receiving end does not exist.'
For now, I'm not even trying to return DOM data; just trying to console.log a message triggered by the extension and returned by the content script. Any idea what the issue might be?
Here's my setup:
manifest.jst
{
"name": "Fetch Test",
"description": "Fetch data from DOM",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "popup.html"
},
"permissions": ["activeTab", "tabs", "scripting"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content_script.js"]
}
]
}
popup.html
<html>
<body>
<div class="container">
<button id="fetch-button">Fetch</button>
</div>
</body>
</html>
<script src="popup.js"></script>
popup.js
document.getElementById("fetch-button").addEventListener("click", function () {
(async () => {
const [tab] = await chrome.tabs.query({
active: true,
lastFocusedWindow: true,
});
const response = await chrome.tabs.sendMessage(tab.id, {
greeting: "hello",
});
console.log(response);
})();
});
content_script.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log(
sender.tab
? "from a content script:" + sender.tab.url
: "from the extension"
);
if (request.greeting === "hello") sendResponse({ farewell: "goodbye" });
});
This sample uses executeScript to get document.title.
manifest.json
{
"name": "Get document.title",
"version": "1.0",
"manifest_version": 3,
"permissions": [
"scripting"
],
"host_permissions": [
"<all_urls>"
],
"action": {
"default_popup": "popup.html"
}
}
popup.html
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
* {
font-size: x-large;
}
</style>
</head>
<body style="min-width:300px">
<div id="title"></div><br>
<script src="popup.js"></script>
</body>
</html>
popup.js
const getTitle = () => {
console.log("getTitle() = " + document.title);
return document.title;
}
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
console.log("Execute Script");
chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
func: getTitle
}, (result) => {
console.log("Recv result = " + result[0].result);
document.getElementById("title").innerText = result[0].result;
});
});
You need to include the javascript files in your popup.html file like so. Does that help?
<html>
<head>
<script src="popup.js"></script>
<script src="content_script.js"></script>
</head>
<body>
<div class="container">
<button id="fetch-button">Fetch</button>
</div>
</body>
</html>
You can try to do a long-lived message passing.
popup.js
const extensionContentScriptPort = () => {
return (async function () {
const currentTabQuery = {
active: true,
currentWindow: true,
};
const currentTabId = (await chrome?.tabs?.query(currentTabQuery))?.[0].id;
return chrome?.tabs?.connect(currentTabId, {
name: 'EXTENSION_CONTENTSCRIPT',
});
})();
};
// Add Event Listener for receiving messages
extensionContentScriptPort.then(port =>
port.onMessage.addListener((extensionContentScriptMsg) => {
console.log(extensionContentScriptMsg);
});
);
// Post message to content script
document.getElementById("fetch-button").addEventListener("click", function () {
extensionContentScriptPort?.then(port => {
port.postMessage({
greeting: "hello"
})
});
});
content_script.js
chrome?.runtime?.onConnect?.addListener(function (extensionContentScriptPort) {
console.assert(extensionContentScriptPort?.name === 'EXTENSION_CONTENTSCRIPT');
extensionContentScriptPort?.onMessage?.addListener(function (
extensionContentScriptMsg,
) {
if (extensionContentScriptMsg?.greetings === "hello") {
return extensionContentScriptPort?.postMessage({
greetings_reply: "Hey, there!"
})
}
}
}

Chrome Extension execute script doesn't render browser content value

All I am trying to do change the value of popup.html on the basis of Specific URL. So I am sending message to background.js when user click on change ID of H2 from popup.html render the content by using specific JavaScript file
manifest.json
{
"manifest_version": 2,
"name": "Helpfullio",
"version": "0.1",
"content_scripts": [{
"matches": [
"*://google.com/*/*",
],
"js": ["jquery-3.2.1.js"]
}],
"browser_action": {
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"]
},
"permissions": ["tabs","http://*/*", "https://*/*"]
}
popup.html
<html>
<head>
</head>
<body>
<h2 id="change">Change ___________</h2>
<script src="popup.js"></script>
</body>
</html>
popup.js
function clickHandler(e) {
chrome.runtime.sendMessage({directive: "popup-click"}, function(response) {
// this.close(); finishes processing request
});
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('change').addEventListener('click', clickHandler);
})
background.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
switch (request.directive) {
case "popup-click":
chrome.tabs.query({
'active': true, 'lastFocusedWindow': true
}, function (tabs) {
var url = tabs[0].url;
var result = url.split('/');
var hostname = result[2];
if("bitlock" == hostname){
chrome.tabs.executeScript(null, {
file: "render.js",
// allFrames: true
});
}else{
hrome.tabs.executeScript(null, {
file: "secondrender.js",
// allFrames: true
});
}
sendResponse({});
});
break;
default:
alert("Unmatched request of '" + request + "' from script to background.js from " + sender);
}
}
);;
JavaScript doesn't render the content of popup.html as it is not finding the elementID "change" . SO here how can I give reference of popup.html file in render.js file
render.js
document.getElementById("change").textContent = 'new text';

XMLHttpRequest status 0 in click event handler

I'm writing a Google Chrome extension to take advantage of an API we have written. The problem I'm having is that the popup.html has a login form, and when the submit button is pressed it calls the necessary authentication code, which involves making a couple of XMLHttpRequests to the API server.
The code is as follows:
authenticate.js
function authenticate(username, password)
{
var xhr = new XMLHttpRequest();
xhr.open("GET", "<api-server>/challenge?username=dummyusername", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
alert(xhr.status);
}
};
xhr.send();
}
/*Gets the username and password textboxes from popup.html and passes their values on to authenticate()*/
function getCredentials()
{
authenticate("test", "test");
}
document.addEventListener("DOMContentLoaded", function() {
var submitBtn = document.getElementById("submitBtn");
if (submitBtn != null) {
submitBtn.onclick = getCredentials;
}
});
popup.html
<!doctype html>
<html>
<head>
<title>Login Page</title>
</head>
<body>
<form>
<label for="username">Username:</label>
<input type="text" id="usernameTxt"><br>
<label for="password">Password:</label>
<input type="password" id="passwordTxt"><br><br>
<input type="submit" id="submitBtn" value="Submit">
</form>
<script src="authenticate.js"></script>
</body>
</html>
manifest.json
{
"manifest_version": 2,
"name": "Chrome Extension",
"description": "Chrome Extension",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"tabs",
"<all_urls>",
"activeTab",
"https://ajax.googleapis.com/",
"<api-server>"
]
}
If, however, I replace:
document.addEventListener("DOMContentLoaded", function() {
var submitBtn = document.getElementById("submitBtn");
if (submitBtn != null) {
submitBtn.onclick = getCredentials;
}
});
with:
document.addEventListener('DOMContentLoaded', function() {
getCredentials();
});
it does the right thing, which leads me to believe it's to do with the fact that it's being called from a click event handler and perhaps somehow the permissions haven't been extended to the button.
I saw this post (Chrome Extension: XMLHttpRequest canceled (status == 0)) and added "<all_urls>" to permissions and that has made no difference.
Cancel the click so the form does not submit.
document.getElementById("submitBtn").addEventListener('click', function(evt){
evt.preventDefault();
getCredentials();
});

Chrome extension browse file (Chrome v33)

I had browsing for files working in chrome extensions but suddenly it stopped working (im guessing because of a chrome upgrade (to v33?))
i have looked around and all answers seem outdated...
here are my files (i got it from this: Upload File as a Form Data through chrome extension)
manifest.json:
{
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"name": "yoyo",
"manifest_version": 2,
"version": "1.0.0",
"browser_action": {
"default_title": "Test Extension",
"default_popup": "popup.html"
},
"permissions": [
"https://www.example.com/uploads"
]
}
popup.html:
<html>
<head>
<script type="text/javascript" src="popup.js"></script>
</head>
<body>
<input type="button" id="button" value="Browse and Upload" />
</body>
</html>
popup.js:
document.addEventListener('DOMContentLoaded', function () {
document.getElementsByTagName('input')[0].addEventListener('click', function () {
chrome.runtime.sendMessage({ action: 'browseAndUpload' }, function(response){});
window.close();
});
});
background.js:
var uploadURL = 'https://www.example.com/uploads';
/* Creates an `input[type="file]` */
var fileChooser = document.createElement('input');
fileChooser.type = 'file';
fileChooser.addEventListener('change', function () {
var file = fileChooser.files[0];
var formData = new FormData();
formData.append(file.name, file);
var xhr = new XMLHttpRequest();
xhr.open('POST', uploadURL, true);
xhr.addEventListener('readystatechange', function (evt) {
console.log('ReadyState: ' + xhr.readyState,
'Status: ' + xhr.status);
});
xhr.send(formData);
form.reset(); // <-- Resets the input so we do get a `change` event,
// even if the user chooses the same file
});
/* Wrap it in a form for resetting */
var form = document.createElement('form');
form.appendChild(fileChooser);
/* Listen for messages from popup */
chrome.runtime.onMessage.addListener(function (msg) {
if (msg.action === 'browseAndUpload') {
fileChooser.click();
}
});

chrome extension sendMessages more than one

Hello i'm trying to send message to popedup window, but when i close popup window end call it(from context menu) again.. it shows all last masseges..
How can i send only one message only to new opened window?
Manifest.json
{
"manifest_version": 2,
"name": "1tst",
"description": "sm txt",
"version": "0.1",
"author": "smwn",
"permissions": [
"activeTab",
"tabs",
"contextMenus"
],
"background": {
"scripts": ["sample.js"]
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["1.js"]
}]
}
sample.js
function genericOnClick(info, tab,selT) {
var vid;
var nw_tb;
chrome.tabs.create({
url: chrome.extension.getURL('1.html'),
active: false
}, function(tab) {
vid = tab.id;
// After the tab has been created, open a window to inject the tab
chrome.windows.create({
tabId: tab.id,
type: 'popup',
focused: true
// incognito, top, left, ...
},function(chromeWindow) {
//vid = chromeWindow.id;
}
);
});
chrome.windows.onCreated.addListener(function(tabb){
nw_tb = tabb.id;
alert("vid: "+vid+" nw_tb: "+nw_tb);
chrome.runtime.sendMessage(vid, {statn: selT});
return;
});
}
var title = "Test '%s' menu item";
var id = chrome.contextMenus.create({"title": title, "contexts":["selection"],
"onclick": function(info,tab){ genericOnClick(info,tab, info.selectionText);}
});
1.html
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script src="1.js"></script>
</head>
<body>
</body>
</html>
1.js
window.onload=function(){
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
sendResponse({metroSTAT: "OK"});
alert(request.statn);
});
}
The problem
Every time genericOnClick() is called, it registers a new listener for the windows.onCreated event. Once registered, the listeners will trigger every time.
The solution
One of the many possible solutions is to "un-register" the listener once it is triggered for the first time (using removeListener()):
// Replace the following block:
chrome.windows.onCreated.addListener(function(tabb){
...
});
// With this:
chrome.windows.onCreated.addListener(function tmpListener(tabb) {
chrome.windows.onCreated.removeListener(tmpListener);
...
});

Categories

Resources