I'm building my first Firefox Web Extension, and I am integrating with an API using OAuth.
我正在构建我的第一个Firefox Web扩展,并且我正在使用OAuth与API集成。
What happens is when the user clicks the icon in the toolbar, it gives them an authentication number to enter into a web page. They then do this, authorize my app and it stores an access token.
当用户点击工具栏中的图标时,它会为他们提供进入网页的身份验证号码。然后他们这样做,授权我的应用程序并存储访问令牌。
Where I'm getting stuck is currently my code relies on the popup window staying open to poll for a response from the responding API. I'm assuming I need to run the poll in a background file, but I'm not sure how I would do this.
我遇到困难的地方当前我的代码依赖弹出窗口保持打开状态来轮询响应API的响应。我假设我需要在后台文件中运行轮询,但我不确定如何执行此操作。
My popup.js
// Set Vars
var successComp = 0;
// Poll to check for authentication
function pollAccessToken(device_code, interval) {
var request = new XMLHttpRequest();
request.open('POST', 'https://private-anon-535ecb43fa-trakt.apiary-mock.com/oauth/device/token');
request.setRequestHeader('Content-Type', 'application/json');
request.onreadystatechange = function () {
if (this.readyState === 4) {
switch (this.status) {
case 200:
// Get Response and put in array
var response = JSON.parse(this.responseText);
// Save Access Token and Refresh Token to storage
chrome.storage.local.set({"access_token": response.access_token, "refresh_token": response.refresh_token});
// Set success notification
chrome.runtime.sendMessage({"title": "Trakt for IMDb Authentication Success", "content": "Awesome, you've authenticated your Trakt account! Enjoy using Trakt for IMDb."});
// Set successComp to 1 so clearTimeout doesn't trigger
successComp = 1;
break;
case 400:
// Request still pending
setTimeout(pollAccessToken.bind(null, device_code).bind(null, interval), interval * 1000);
break;
case 404:
// Display Request not found/invalid error
chrome.runtime.sendMessage({"title": "Trakt for IMDb Authentication Error", "content": "Whoops, looks like there was an error authenticating your Trakt account. Please try again."});
break;
case 409:
// Code already used
chrome.runtime.sendMessage({"title": "Trakt for IMDb already approved", "content": "Whoops, looks like you've already approved this code. If you continue to have issues, please try again."});
break;
case 410:
// Code Expired
chrome.runtime.sendMessage({"title": "Trakt for IMDb Authentication Token Error", "content": "Whoops, looks like your token expired and there was an error authenticating your Trakt account. Please try again"});
break;
case 418:
// Code Denied
chrome.runtime.sendMessage({"title": "Trakt for IMDb Authentication Denied", "content": "Oh no, it looks like you denied us access to your account! If you didn't mean to do this, please try again."});
break;
case 429:
// Slow down polling
setTimeout(pollAccessToken.bind(null, device_code).bind(null, interval), interval * 1100);
break;
default:
// Request still pending
setTimeout(pollAccessToken.bind(null, device_code).bind(null, interval), interval * 1000);
break;
}
}
};
var body = {
'code': device_code,
'client_id': APP_KEY,
'client_secret': APP_SEC
};
request.send(JSON.stringify(body));
}
// Get and display authentication
function outputAuth() {
var request = new XMLHttpRequest();
request.open('POST', 'https://private-anon-535ecb43fa-trakt.apiary-mock.com/oauth/device/code');
request.setRequestHeader('Content-Type', 'application/json');
request.onreadystatechange = function () {
if (this.readyState === 4) {
// Get Response and put in array
var response = JSON.parse(this.responseText);
// Output authentication data
document.body.innerHTML = '<section id="traktLogo"><img src="../icons/trakt-logo.png" width="100px" height="100px" alt="Trakt" /></section><h1>Trakt Authentication</h1><h2>Enter the following code into the activation page.</h2><code>' + response.user_code + '</code><a href="' + response.verification_url + '" id="activation" target="_newtab">Activation Page</a>';
var pollAccess = pollAccessToken(response.device_code, response.interval);
setTimeout(stopPolling, response.expires_in * 1000);
}
};
var body = {
'client_id': APP_KEY
};
request.send(JSON.stringify(body));
}
// Stop Polling Function
function stopPolling() {
if (successComp === 0) {
// Response polling expired
clearTimeout(pollAccess);
chrome.runtime.sendMessage({"title": "Trakt for IMDb Authentication Timed Out", "content": "Whoops, looks like you took too long in authenticating your Trakt account. Please try again."});
}
}
// Check if Access Token Exists
chrome.storage.local.get("access_token", function (result) {
if (result.access_token && typeof result.access_token !== undefined) {
// Output Profile Page
document.body.innerHTML = '<p>Profile Page</p>';
} else {
// Output Authenctication Page
outputAuth();
}
});
My background.js
// Display a Notification
function notify(message) {
chrome.notifications.create({
"type": "basic",
"title": message.title,
"message": message.content,
"iconUrl": chrome.extension.getURL("icons/icon-256.png")
});
}
/*
Assign `notify()` as a listener to messages from the content script.
*/
chrome.runtime.onMessage.addListener(notify);
I'm happy enough to send the polling code to the background.js file, I'm just not quite sure how I would trigger it. It's also very important that I have the code that will stop the pollAccessToken
function from running after x amount of minutes as specified by the API docs.
我很高兴将轮询代码发送到background.js文件,我只是不确定如何触发它。同样非常重要的是,我有一些代码可以阻止pollAccessToken函数在API文档指定的x分钟后运行。
Full source code can be previewed at Trakt for IMDb on Github
完整的源代码可以在Trakt上预览Github上的IMDb
Polling API docs can be found at Trakt.tv API on Apiary
可以在Apiary上的Trakt.tv API中找到轮询API文档
1 个解决方案
#1
0
I think I've got it working with the following script. If anyone can tell me why the following WOULDN'T work how I want it to would be much appreciated :)
我想我已经使用以下脚本了。如果有人可以告诉我为什么以下不会工作我想要它将非常感谢:)
popup.js
// Get and display authentication
function outputAuth() {
var request = new XMLHttpRequest();
request.open('POST', 'https://private-anon-535ecb43fa-trakt.apiary-mock.com/oauth/device/code');
request.setRequestHeader('Content-Type', 'application/json');
request.onreadystatechange = function () {
if (this.readyState === 4) {
// Get Response and put in array
var response = JSON.parse(this.responseText);
// Output authentication data
document.body.innerHTML = '<section id="traktLogo"><img src="../icons/trakt-logo.png" width="100px" height="100px" alt="Trakt" /></section><h1>Trakt Authentication</h1><h2>Enter the following code into the activation page.</h2><code>' + response.user_code + '</code><a href="' + response.verification_url + '" id="activation" target="_newtab">Activation Page</a>';
chrome.runtime.sendMessage({"type": "pollRequest", "device_code": response.device_code, "interval": response.interval, "expires_in": response.expires_in});
}
};
var body = {
'client_id': APP_KEY
};
request.send(JSON.stringify(body));
}
// Check if Access Token Exists
chrome.storage.local.get("access_token", function (result) {
if (result.access_token && typeof result.access_token !== undefined) {
// Output Profile Page
document.body.innerHTML = '<p>Profile Page</p>';
} else {
// Output Authenctication Page
outputAuth();
}
});
background.js
// key.js - Trakt for IMDb by dpDesignz
var APP_KEY = '';
var APP_SEC = '';
// Display a Notification
function notify(message) {
chrome.notifications.create({
"type": "basic",
"title": message.title,
"message": message.content,
"iconUrl": chrome.extension.getURL("icons/icon-256.png")
});
}
// Set Vars
var successComp = 0;
// Poll to check for authentication
function pollAccessToken(device_code, interval) {
var request = new XMLHttpRequest();
request.open('POST', 'https://private-anon-535ecb43fa-trakt.apiary-mock.com/oauth/device/token');
request.setRequestHeader('Content-Type', 'application/json');
request.onreadystatechange = function () {
if (this.readyState === 4) {
switch (this.status) {
case 200:
// Get Response and put in array
var response = JSON.parse(this.responseText);
// Save Access Token and Refresh Token to storage
chrome.storage.local.set({"access_token": response.access_token, "refresh_token": response.refresh_token});
// Set success notification
notify({"title": "Trakt for IMDb Authentication Success", "content": "Awesome, you've authenticated your Trakt account! Enjoy using Trakt for IMDb."});
// Set successComp to 1 so clearTimeout doesn't trigger
successComp = 1;
break;
case 400:
// Request still pending
setTimeout(pollAccessToken.bind(null, device_code).bind(null, interval), interval * 1000);
break;
case 404:
// Display Request not found/invalid error
notify({"title": "Trakt for IMDb Authentication Error", "content": "Whoops, looks like there was an error authenticating your Trakt account. Please try again."});
break;
case 409:
// Code already used
notify({"title": "Trakt for IMDb already approved", "content": "Whoops, looks like you've already approved this code. If you continue to have issues, please try again."});
break;
case 410:
// Code Expired
notify({"title": "Trakt for IMDb Authentication Token Error", "content": "Whoops, looks like your token expired and there was an error authenticating your Trakt account. Please try again"});
break;
case 418:
// Code Denied
notify({"title": "Trakt for IMDb Authentication Denied", "content": "Oh no, it looks like you denied us access to your account! If you didn't mean to do this, please try again."});
break;
case 429:
// Slow down polling
setTimeout(pollAccessToken.bind(null, device_code).bind(null, interval), interval * 1100);
break;
default:
// Request still pending
setTimeout(pollAccessToken.bind(null, device_code).bind(null, interval), interval * 1000);
break;
}
}
};
var body = {
'code': device_code,
'client_id': APP_KEY,
'client_secret': APP_SEC
};
request.send(JSON.stringify(body));
}
// Stop Polling Function
function stopPolling() {
if (successComp === 0) {
// Response polling expired
clearTimeout(pollAccess);
notify({"title": "Trakt for IMDb Authentication Timed Out", "content": "Whoops, looks like you took too long in authenticating your Trakt account. Please try again."});
}
}
// Assign functions based on type
chrome.runtime.onMessage.addListener(function(data) {
switch (data.type) {
case "notification":
notify(data);
break;
case "pollRequest":
var pollAccess = pollAccessToken(data.device_code, data.interval);
setTimeout(stopPolling, data.expires_in * 1000);
break;
}
});
#1
0
I think I've got it working with the following script. If anyone can tell me why the following WOULDN'T work how I want it to would be much appreciated :)
我想我已经使用以下脚本了。如果有人可以告诉我为什么以下不会工作我想要它将非常感谢:)
popup.js
// Get and display authentication
function outputAuth() {
var request = new XMLHttpRequest();
request.open('POST', 'https://private-anon-535ecb43fa-trakt.apiary-mock.com/oauth/device/code');
request.setRequestHeader('Content-Type', 'application/json');
request.onreadystatechange = function () {
if (this.readyState === 4) {
// Get Response and put in array
var response = JSON.parse(this.responseText);
// Output authentication data
document.body.innerHTML = '<section id="traktLogo"><img src="../icons/trakt-logo.png" width="100px" height="100px" alt="Trakt" /></section><h1>Trakt Authentication</h1><h2>Enter the following code into the activation page.</h2><code>' + response.user_code + '</code><a href="' + response.verification_url + '" id="activation" target="_newtab">Activation Page</a>';
chrome.runtime.sendMessage({"type": "pollRequest", "device_code": response.device_code, "interval": response.interval, "expires_in": response.expires_in});
}
};
var body = {
'client_id': APP_KEY
};
request.send(JSON.stringify(body));
}
// Check if Access Token Exists
chrome.storage.local.get("access_token", function (result) {
if (result.access_token && typeof result.access_token !== undefined) {
// Output Profile Page
document.body.innerHTML = '<p>Profile Page</p>';
} else {
// Output Authenctication Page
outputAuth();
}
});
background.js
// key.js - Trakt for IMDb by dpDesignz
var APP_KEY = '';
var APP_SEC = '';
// Display a Notification
function notify(message) {
chrome.notifications.create({
"type": "basic",
"title": message.title,
"message": message.content,
"iconUrl": chrome.extension.getURL("icons/icon-256.png")
});
}
// Set Vars
var successComp = 0;
// Poll to check for authentication
function pollAccessToken(device_code, interval) {
var request = new XMLHttpRequest();
request.open('POST', 'https://private-anon-535ecb43fa-trakt.apiary-mock.com/oauth/device/token');
request.setRequestHeader('Content-Type', 'application/json');
request.onreadystatechange = function () {
if (this.readyState === 4) {
switch (this.status) {
case 200:
// Get Response and put in array
var response = JSON.parse(this.responseText);
// Save Access Token and Refresh Token to storage
chrome.storage.local.set({"access_token": response.access_token, "refresh_token": response.refresh_token});
// Set success notification
notify({"title": "Trakt for IMDb Authentication Success", "content": "Awesome, you've authenticated your Trakt account! Enjoy using Trakt for IMDb."});
// Set successComp to 1 so clearTimeout doesn't trigger
successComp = 1;
break;
case 400:
// Request still pending
setTimeout(pollAccessToken.bind(null, device_code).bind(null, interval), interval * 1000);
break;
case 404:
// Display Request not found/invalid error
notify({"title": "Trakt for IMDb Authentication Error", "content": "Whoops, looks like there was an error authenticating your Trakt account. Please try again."});
break;
case 409:
// Code already used
notify({"title": "Trakt for IMDb already approved", "content": "Whoops, looks like you've already approved this code. If you continue to have issues, please try again."});
break;
case 410:
// Code Expired
notify({"title": "Trakt for IMDb Authentication Token Error", "content": "Whoops, looks like your token expired and there was an error authenticating your Trakt account. Please try again"});
break;
case 418:
// Code Denied
notify({"title": "Trakt for IMDb Authentication Denied", "content": "Oh no, it looks like you denied us access to your account! If you didn't mean to do this, please try again."});
break;
case 429:
// Slow down polling
setTimeout(pollAccessToken.bind(null, device_code).bind(null, interval), interval * 1100);
break;
default:
// Request still pending
setTimeout(pollAccessToken.bind(null, device_code).bind(null, interval), interval * 1000);
break;
}
}
};
var body = {
'code': device_code,
'client_id': APP_KEY,
'client_secret': APP_SEC
};
request.send(JSON.stringify(body));
}
// Stop Polling Function
function stopPolling() {
if (successComp === 0) {
// Response polling expired
clearTimeout(pollAccess);
notify({"title": "Trakt for IMDb Authentication Timed Out", "content": "Whoops, looks like you took too long in authenticating your Trakt account. Please try again."});
}
}
// Assign functions based on type
chrome.runtime.onMessage.addListener(function(data) {
switch (data.type) {
case "notification":
notify(data);
break;
case "pollRequest":
var pollAccess = pollAccessToken(data.device_code, data.interval);
setTimeout(stopPolling, data.expires_in * 1000);
break;
}
});