Skip to content

Commit

Permalink
fix the ability to restore tokens from a JSON text file
Browse files Browse the repository at this point in the history
previous methodology:
=====================
* popup window:
  - dynamically creates an input file element
  - click event triggers the element to open the file chooser dialog
  - processes the list of selected files by:
    * reading the content of each file
    * parsing its JSON
    * passing the resulting object in a message to the background page
* background page:
  - merges backup data with the tokens already saved in local storage
  - updates local storage with this new aggregate value
  - updates the popup window

problem with previous methodology:
==================================
* only works if the browser doesn't close the popup window
  before the data is passed to the background page
* many browsers do close the popup window
  when the file input dialog is triggered for selection of input files

new methodology:
================
* popup window:
  - sends a message to the background page
* background page:
  - opens a new tab and loads a static html page
* static html page:
  - dynamically creates an input file element
  - adds a click event handler to the element,
    which requires user interaction to trigger
  - the click event handler processes the list of selected files by:
    * reading the content of each file
    * parsing its JSON
    * passing the resulting object in a message to the background page
  - the click event handler also tracks the count of files pending
    * after the processing of all files is complete,
      sends a final message to the background page
* background page:
  - merges backup data with the tokens already saved in local storage
  - updates local storage with this new aggregate value
  - closes the tab containing the static html page

comparison between methodologies:
=================================
* previous methodology:
  - pros:
    * simpler implementation
    * more elegant user experience
  - cons:
    * doesn't work in many browsers
* new methodology:
  - pros:
    * works in all supported browsers
  - cons:
    * much more complicated implementation
    * less elegant user experience,
      which requires interaction with a standalone page in a new tab
  • Loading branch information
warren-bank committed Feb 1, 2022
1 parent 8283f46 commit 0ab56ce
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 59 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "privacy-pass",
"version": "3.6.5",
"version": "3.6.6",
"private": true,
"contributors": [
"Suphanat Chunhapanya <[email protected]>",
Expand Down
2 changes: 1 addition & 1 deletion public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"description": "__MSG_appDescription__",
"version": "3.6.5",
"version": "3.6.6",
"manifest_version": 2,
"default_locale": "en",
"icons": {
Expand Down
9 changes: 9 additions & 0 deletions public/restore.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="root"></div>
</body>
</html>
51 changes: 40 additions & 11 deletions src/background/listeners/messageListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,21 @@ function addPasses(providerID: string, newTokensArray: string[]): boolean {
}
}

export function handleReceivedMessage(request: any, _sender: chrome.runtime.MessageSender, sendResponse: Function): void {
function restorePasses(backup: {[key: string]: string[]} | void): boolean {
let did_restore: boolean = false;

if (backup !== undefined) {
for (const providerID in backup) {
if (addPasses(providerID, backup[providerID]) && !did_restore) {
did_restore = true;
}
}
}

return did_restore;
}

export function handleReceivedMessage(request: any, sender: chrome.runtime.MessageSender, sendResponse: Function): void {

// -------------------------------------------------------------------------
if (request.tokensCount === true) {
Expand All @@ -80,23 +94,37 @@ export function handleReceivedMessage(request: any, _sender: chrome.runtime.Mess

// -------------------------------------------------------------------------
if (request.restore === true) {
const backup: {[key: string]: string[]} | void = request.backup;
let did_restore: boolean = false;
if (request.tab !== undefined) {
if (request.tab.open === true) {
chrome.tabs.create({ url: '/restore.html', active: true });

if (backup !== undefined) {
for (const providerID in backup) {
if (addPasses(providerID, backup[providerID]) && !did_restore) {
did_restore = true;
sendResponse();
return;
}

if (request.tab.close === true) {
if ((sender.tab !== undefined) && (sender.tab.id !== undefined) && (sender.tab.id !== chrome.tabs.TAB_ID_NONE)) {
chrome.tabs.remove(sender.tab.id);
}

sendResponse();
return;
}
}

if (did_restore) {
// Update the browser action icon after restoring tokens.
forceUpdateIcon();
if (request.backup !== undefined) {
const did_restore: boolean = restorePasses(request.backup);

if (did_restore) {
// Update the browser action icon after restoring tokens.
forceUpdateIcon();
}

sendResponse(did_restore);
return;
}

sendResponse(did_restore);
sendResponse();
return;
}

Expand All @@ -107,6 +135,7 @@ export function handleReceivedMessage(request: any, _sender: chrome.runtime.Mess
// Update the browser action icon after clearing the tokens.
forceUpdateIcon();

sendResponse();
return;
}

Expand Down
46 changes: 1 addition & 45 deletions src/popup/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,51 +71,7 @@ const reducer = (state: any | undefined, action: Action) => {
});
return state;
case 'RESTORE_TOKENS':
(async (): Promise<void> => {

const readFile = function (event: Event) {
event.stopPropagation();
event.stopImmediatePropagation();

const input: HTMLInputElement = <HTMLInputElement>event.target;
const files: FileList | null = input.files;
if (files === null) return;

for (let file_index=0; file_index < files.length; file_index++) {
const reader = new FileReader();

reader.onload = function(){
try {
if ((typeof reader.result === 'string') && (reader.result.length > 0)) {
const backupJSON: string = reader.result;
const backup: {[key: string]: string[]} = JSON.parse(backupJSON);

chrome.runtime.sendMessage({ restore: true, backup }, (response: any) => {
if (response === true) {
store.dispatch({ type: 'OBTAIN_STATE' });
}
});
}
}
catch(e) {}
};

reader.readAsText(
files[file_index]
);
}
};

try {
const input = window.document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'text/plain, application/json, .txt, .json');
input.addEventListener('change', readFile);
input.click();
}
catch(e) {}
})();

chrome.runtime.sendMessage({ restore: true, tab: { open: true } });
return state;
case 'CLEAR_TOKENS':
chrome.runtime.sendMessage({ clear: true });
Expand Down
78 changes: 78 additions & 0 deletions src/restore/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
function handleBackupFileImport(event: Event): void {
event.stopPropagation();
event.stopImmediatePropagation();

const input: HTMLInputElement = <HTMLInputElement>event.target;
const files: FileList | null = input.files;
if (files === null) return;

let remaining_files = files.length;

const onFileReadComplete = () => {
remaining_files--;

if (remaining_files <= 0) {
chrome.runtime.sendMessage({ restore: true, tab: { close: true } });
}
}

for (let file_index=0; file_index < files.length; file_index++) {
const reader = new FileReader();

reader.onload = function(){
try {
if ((typeof reader.result === 'string') && (reader.result.length > 0)) {
const backupJSON: string = reader.result;
const backup: {[key: string]: string[]} = JSON.parse(backupJSON);

chrome.runtime.sendMessage({ restore: true, backup });
}
}
catch(e) {}
onFileReadComplete();
};

reader.onerror = onFileReadComplete;
reader.onabort = onFileReadComplete;

reader.readAsText(
files[file_index]
);
}
}


window.addEventListener('DOMContentLoaded', (event) => {
event.stopPropagation();
event.stopImmediatePropagation();

const appName = chrome.i18n.getMessage('appName');
const ctaRestorePasses = chrome.i18n.getMessage('ctaRestorePasses');

window.document.title = appName + ': ' + ctaRestorePasses;

const input = window.document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'text/plain, application/json, .txt, .json');
input.setAttribute('multiple', '');
input.addEventListener('change', handleBackupFileImport);

const root = window.document.getElementById('root');
if (root !== null) {
const heading = window.document.createElement('h2');
heading.appendChild(
window.document.createTextNode(appName)
);

const subheading = window.document.createElement('h3');
subheading.appendChild(
window.document.createTextNode(ctaRestorePasses)
);

root.appendChild(heading);
root.appendChild(subheading);
root.appendChild(input);
}

input.click();
});
9 changes: 9 additions & 0 deletions src/restore/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"isolatedModules": false
},
"extends": "../../tsconfig.json",
"include": [
"."
]
}
3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
},
{
"path": "./src/popup"
},
{
"path": "./src/restore"
}
]
}
22 changes: 21 additions & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,25 @@ const popup = {
],
};

const restore = {
...common,
entry: {
restore: path.resolve('src/restore/index.ts'),
},
module: {
rules: [tsloader],
},
resolve: {
extensions: ['.ts', '.js'],
},
plugins: [
new HtmlWebpackPlugin({
chunks: ['restore'],
filename: 'restore.html',
template: 'public/restore.html',
}),
],
};

// Mutiple targets for webpack: https://webpack.js.org/concepts/targets/#multiple-targets
export default [background, popup];
export default [background, popup, restore];

0 comments on commit 0ab56ce

Please sign in to comment.