mirror of
https://github.com/twofas/2fas-browser-extension.git
synced 2024-11-21 17:49:56 +01:00
commit
bfdf9c05cd
@ -431,7 +431,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 54;
|
||||
CURRENT_PROJECT_VERSION = 57;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = ZY8UR5ADFW;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@ -445,7 +445,7 @@
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 1.6.4;
|
||||
MARKETING_VERSION = 1.7.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@ -467,7 +467,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 54;
|
||||
CURRENT_PROJECT_VERSION = 57;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = ZY8UR5ADFW;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@ -481,7 +481,7 @@
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 1.6.4;
|
||||
MARKETING_VERSION = 1.7.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@ -505,7 +505,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "macOS (App)/2FAS - Two factor authentication.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 54;
|
||||
CURRENT_PROJECT_VERSION = 57;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = ZY8UR5ADFW;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@ -520,7 +520,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 1.6.4;
|
||||
MARKETING_VERSION = 1.7.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@ -546,7 +546,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 54;
|
||||
CURRENT_PROJECT_VERSION = 57;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = ZY8UR5ADFW;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@ -561,7 +561,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 1.6.4;
|
||||
MARKETING_VERSION = 1.7.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
|
@ -49,13 +49,13 @@
|
||||
16 - inputFocus
|
||||
17 - contentOnMessage
|
||||
18 - neverShowNotificationInfo
|
||||
*19 - openOptionsPage [redundant]
|
||||
39 - removedNodes - loadFromLocalStorage
|
||||
40 - removedNodes - saveToLocalStorage
|
||||
41 - hiddenNodes - loadFromLocalStorage
|
||||
42 - hiddenNodes - saveToLocalStorage
|
||||
43 - pageLoadComplete - loadFromLocalStorage
|
||||
44 - pageLoadComplete - saveToLocalStorage
|
||||
*19 - openOptionsPage [deprecated]
|
||||
*39 - removedNodes - loadFromLocalStorage [deprecated]
|
||||
*40 - removedNodes - saveToLocalStorage [deprecated]
|
||||
*41 - hiddenNodes - loadFromLocalStorage [deprecated]
|
||||
*42 - hiddenNodes - saveToLocalStorage [deprecated]
|
||||
*43 - pageLoadComplete - loadFromLocalStorage [deprecated]
|
||||
*44 - pageLoadComplete - saveToLocalStorage [deprecated]
|
||||
46 - clickSubmit - loadFromLocalStorage
|
||||
|
||||
// INSTALL PAGE
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12
package.json
12
package.json
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "2fas-browser-extension",
|
||||
"version": "1.6.4",
|
||||
"version": "1.7.0",
|
||||
"description": "This is the official Browser Extension for the Open Source 2FAS project.",
|
||||
"engines": {
|
||||
"node": "20.9.0"
|
||||
"node": "20.11.1"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "npx -y rimraf --glob ./public/*",
|
||||
@ -23,7 +23,7 @@
|
||||
"safari-dev": "yon clean && yon generate-locales && npx -y cross-env EXT_PLATFORM=Safari node_modules/.bin/webpack --mode development --progress --config webpack/development.config.js",
|
||||
"safari-prod": "yon clean && yon generate-locales && yon browserlist-update && npx -y cross-env EXT_PLATFORM=Safari NODE_ENV=production node_modules/.bin/webpack --mode production --progress --config webpack/production.config.js",
|
||||
"all-build": "npx -y rimraf --glob ./build/* && yon generate-license-info && yon chrome-build && yon opera-build && yon firefox-build && yon edge-build",
|
||||
"browserlist-update": "npx -y update-browserslist-db@latest",
|
||||
"browserlist-update": "npx -y browserslist@latest --update-db",
|
||||
"loco-export": "node webpack/utils/locoExport.js",
|
||||
"loco-import": "node webpack/utils/locoImport.js",
|
||||
"check-build-directory": "node webpack/utils/checkBuildDirectoryExists.js",
|
||||
@ -76,7 +76,7 @@
|
||||
"eslint-plugin-n": "^16.6.2",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-standard": "^5.0.0",
|
||||
"eslint-webpack-plugin": "^4.0.1",
|
||||
"eslint-webpack-plugin": "^4.1.0",
|
||||
"exports-loader": "^5.0.0",
|
||||
"file-loader": "^6.0.0",
|
||||
"html-loader": "^5.0.0",
|
||||
@ -84,13 +84,13 @@
|
||||
"mini-css-extract-plugin": "^2.8.1",
|
||||
"noop-loader": "^1.0.0",
|
||||
"path": "^0.12.7",
|
||||
"postcss": "^8.4.35",
|
||||
"postcss": "^8.4.36",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"postcss-sass": "^0.5.0",
|
||||
"precss": "^4.0.0",
|
||||
"require-dir": "^1.2.0",
|
||||
"rimraf": "^5.0.1",
|
||||
"sass": "^1.71.1",
|
||||
"sass": "^1.72.0",
|
||||
"sass-loader": "^14.1.1",
|
||||
"source-map-loader": "^5.0.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
|
@ -35,10 +35,10 @@
|
||||
"errorStorageIntegrityMessage": "Please reinstall browser extension or contact with 2FAS Support on Discord",
|
||||
"warningTooSoonTitle": "Wait a moment",
|
||||
"warningTooSoonMessage": "Please wait DIFF seconds before sending another request.",
|
||||
"warningSelectInputTitle": "Select the text field first",
|
||||
"warningSelectInputMessage": "Select the text field for the 2FA token then click the extension icon or use the chosen shortcut.",
|
||||
"successPushSentTitle": "Push sent",
|
||||
"successPushSentMessage": "Please check your phone and accept your login request.",
|
||||
"successPushSentClipboardTitle": "Push sent",
|
||||
"successPushSentClipboardMessage": "Please check your phone and accept your login request. Copy your token and paste it into the correct input on the website.",
|
||||
"successExtNameUpdatedTitle": "Success",
|
||||
"successExtNameUpdatedMessage": "Extension name updated",
|
||||
"successDeviceDisconnectedTitle": "Success",
|
||||
@ -56,6 +56,8 @@
|
||||
"infoUnsupportedProtocolMessage": "Only HTTP and HTTPS protocols are supported by 2FAS Extension",
|
||||
"infoBrowserActionWithoutTabTitle": "Info",
|
||||
"infoBrowserActionWithoutTabMessage": "Using outside the browser is not supported by 2FAS Extension",
|
||||
"infoCopiedToClipboardTitle": "Successfully copied to clipboard",
|
||||
"infoCopiedToClipboardMessage": "You can now paste the token into the input field",
|
||||
"infoTestTitle": "2FAS Notification",
|
||||
"infoTestMessage": "Hi! This is just a test"
|
||||
}
|
6
src/_locales/en/token.json
Normal file
6
src/_locales/en/token.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"tokenHeader": "Your token",
|
||||
"tokenCopy": "Copy",
|
||||
"tokenCopied": "Copied",
|
||||
"tokenDescription": "Copy the token and paste it in the input field. The token will expire in 30 seconds."
|
||||
}
|
@ -17,13 +17,25 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
/* global HTMLElement */
|
||||
const getChildNodes = node => {
|
||||
if (!(node instanceof HTMLElement)) {
|
||||
return [];
|
||||
const config = require('../../config');
|
||||
const TwoFasNotification = require('../../notification');
|
||||
const saveToLocalStorage = require('../../localStorage/saveToLocalStorage');
|
||||
|
||||
const handleFrontElement = async (activeElements, tabId, storage) => {
|
||||
let properElements = [];
|
||||
|
||||
if (activeElements && activeElements.length > 0) {
|
||||
properElements = activeElements.filter(el => el.id && (el.nodeName === 'input' || el.nodeName === 'textarea'));
|
||||
}
|
||||
|
||||
return Array.from(node.getElementsByTagName('*'));
|
||||
if (properElements.length > 0) {
|
||||
const tabData = storage[`tabData-${tabId}`] || {};
|
||||
tabData.lastFocusedInput = properElements[0].id;
|
||||
await saveToLocalStorage({ [`tabData-${tabId}`]: tabData }, storage);
|
||||
return TwoFasNotification.show(config.Texts.Success.PushSent, tabId);
|
||||
}
|
||||
|
||||
return TwoFasNotification.show(config.Texts.Success.PushSentClipboard, tabId);
|
||||
};
|
||||
|
||||
module.exports = getChildNodes;
|
||||
module.exports = handleFrontElement;
|
@ -32,6 +32,7 @@ exports.dummyGetLocalStorage = require('./dummyGetLocalStorage');
|
||||
exports.generateDefaultStorage = require('./generateDefaultStorage');
|
||||
exports.getBrowserInfo = require('./getBrowserInfo');
|
||||
exports.getOSName = require('./getOSName');
|
||||
exports.handleFrontElement = require('./handleFrontElement');
|
||||
exports.initBEAction = require('./initBEAction');
|
||||
exports.onCommand = require('./onCommand');
|
||||
exports.onConnect = require('./onConnect');
|
||||
@ -41,6 +42,7 @@ exports.onMessage = require('./onMessage');
|
||||
exports.onStartup = require('./onStartup');
|
||||
exports.openBrowserPage = require('./openBrowserPage');
|
||||
exports.openInstallPage = require('./openInstallPage');
|
||||
exports.sendMessageToAllFrames = require('./sendMessageToAllFrames');
|
||||
exports.sendNotificationInfo = require('./sendNotificationInfo');
|
||||
exports.setIcon = require('./setIcon');
|
||||
exports.subscribeChannel = require('./subscribeChannel');
|
||||
|
@ -23,6 +23,8 @@ const subscribeChannel = require('./subscribeChannel');
|
||||
const TwoFasNotification = require('../../notification');
|
||||
const SDK = require('../../sdk');
|
||||
const storeLog = require('../../partials/storeLog');
|
||||
const sendMessageToAllFrames = require('./sendMessageToAllFrames');
|
||||
const handleFrontElement = require('./handleFrontElement');
|
||||
|
||||
const initBEAction = (url, tab, storageData) => {
|
||||
const now = new Date().getTime();
|
||||
@ -36,10 +38,6 @@ const initBEAction = (url, tab, storageData) => {
|
||||
|
||||
const tabData = storage[`tabData-${tab.id}`];
|
||||
|
||||
if (!storage[`tabData-${tab?.id}`]?.lastFocusedInput) {
|
||||
return TwoFasNotification.show(config.Texts.Warning.SelectInput, tab?.id);
|
||||
}
|
||||
|
||||
if (!storage[`tabData-${tab?.id}`]?.lastAction) {
|
||||
condition = true;
|
||||
} else {
|
||||
@ -71,7 +69,8 @@ const initBEAction = (url, tab, storageData) => {
|
||||
});
|
||||
})
|
||||
.then(channel => channel.connect())
|
||||
.then(() => TwoFasNotification.show(config.Texts.Success.PushSent, tab?.id))
|
||||
.then(() => sendMessageToAllFrames(tab?.id, { action: 'getActiveElement' }))
|
||||
.then(elements => handleFrontElement(elements, tab?.id, storage))
|
||||
.catch(async err => {
|
||||
await storeLog('error', 5, err, tabData?.url);
|
||||
return TwoFasNotification.show(config.Texts.Error.UndefinedError, tab?.id);
|
||||
|
@ -21,6 +21,7 @@
|
||||
const getBrowserInfo = require('./getBrowserInfo');
|
||||
const generateDefaultStorage = require('./generateDefaultStorage');
|
||||
const storeLog = require('../../partials/storeLog');
|
||||
const TwoFasNotification = require('../../notification');
|
||||
|
||||
const onMessage = (request, sender) => {
|
||||
return new Promise(resolve => {
|
||||
@ -56,6 +57,14 @@ const onMessage = (request, sender) => {
|
||||
.catch(async err => await storeLog('error', 37, err, 'storageReset'));
|
||||
}
|
||||
|
||||
case 'notificationOnBackground': {
|
||||
if (!request.data) {
|
||||
return resolve({ status: 'No data' });
|
||||
}
|
||||
|
||||
return TwoFasNotification.show(request.data, request.tabID);
|
||||
}
|
||||
|
||||
default: {
|
||||
return resolve({ status: 'Empty action' });
|
||||
}
|
||||
|
@ -17,29 +17,30 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const updateEventListener = require('./updateEventListener');
|
||||
const inputFocus = require('./inputFocus');
|
||||
const browser = require('webextension-polyfill');
|
||||
|
||||
const addInputListener = (elements, tabID) => {
|
||||
if (!Array.isArray(elements) || elements?.length <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let func = event => inputFocus(event, tabID);
|
||||
const sendMessageToAllFrames = async (tabId, message) => {
|
||||
const frames = await browser.webNavigation.getAllFrames({ tabId });
|
||||
|
||||
elements.map(input => {
|
||||
if (input?.dataset?.twofasInputListener === 'true' && input?.dataset.twofasInput) {
|
||||
if (input === document.activeElement || input.matches(':focus')) {
|
||||
return func({ target: input });
|
||||
} else {
|
||||
return Promise.all(frames.map(frame => {
|
||||
return browser.tabs.sendMessage(tabId, message, { frameId: frame.frameId }).catch(() => Promise.resolve(false));
|
||||
})).then(res => {
|
||||
return res.map(frame => {
|
||||
if (!frame) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return updateEventListener(input, func);
|
||||
});
|
||||
|
||||
func = null;
|
||||
switch (frame?.status) {
|
||||
case 'activeElement': {
|
||||
return frame;
|
||||
}
|
||||
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}).catch(() => false);
|
||||
};
|
||||
|
||||
module.exports = addInputListener;
|
||||
module.exports = sendMessageToAllFrames;
|
@ -23,7 +23,7 @@ const t = require('./_locales/en/notifications.json');
|
||||
const config = {
|
||||
WebSocketTimeout: 3, // in minutes
|
||||
ResendPushTimeout: 10, // in seconds
|
||||
ExtensionVersion: '1.6.4',
|
||||
ExtensionVersion: '1.7.0',
|
||||
|
||||
Texts: {
|
||||
Error: {
|
||||
@ -104,10 +104,6 @@ const config = {
|
||||
Title: browser.i18n.getMessage('warningTooSoonTitle') || t.warningTooSoonTitle,
|
||||
Message: (browser.i18n.getMessage('warningTooSoonMessage') || t.warningTooSoonMessage).replace('DIFF', 10 - Math.round(diff))
|
||||
}
|
||||
},
|
||||
SelectInput: {
|
||||
Title: browser.i18n.getMessage('warningSelectInputTitle') || t.warningSelectInputTitle,
|
||||
Message: browser.i18n.getMessage('warningSelectInputMessage') || t.warningSelectInputMessage
|
||||
}
|
||||
},
|
||||
Success: {
|
||||
@ -115,6 +111,10 @@ const config = {
|
||||
Title: browser.i18n.getMessage('successPushSentTitle') || t.successPushSentTitle,
|
||||
Message: browser.i18n.getMessage('successPushSentMessage') || t.successPushSentMessage
|
||||
},
|
||||
PushSentClipboard: {
|
||||
Title: browser.i18n.getMessage('successPushSentClipboardTitle') || t.successPushSentClipboardTitle,
|
||||
Message: browser.i18n.getMessage('successPushSentClipboardMessage') || t.successPushSentClipboardMessage
|
||||
},
|
||||
ExtNameUpdated: {
|
||||
Title: browser.i18n.getMessage('successExtNameUpdatedTitle') || t.successExtNameUpdatedTitle,
|
||||
Message: browser.i18n.getMessage('successExtNameUpdatedMessage') || t.successExtNameUpdatedMessage
|
||||
@ -150,10 +150,20 @@ const config = {
|
||||
Title: browser.i18n.getMessage('infoBrowserActionWithoutTabTitle') || t.infoBrowserActionWithoutTabTitle,
|
||||
Message: browser.i18n.getMessage('infoBrowserActionWithoutTabMessage') || t.infoBrowserActionWithoutTabMessage
|
||||
},
|
||||
CopiedToClipboard: {
|
||||
Title: browser.i18n.getMessage('infoCopiedToClipboardTitle') || t.infoCopiedToClipboardTitle,
|
||||
Message: browser.i18n.getMessage('infoCopiedToClipboardMessage') || t.infoCopiedToClipboardMessage
|
||||
},
|
||||
Test: {
|
||||
Title: browser.i18n.getMessage('infoTestTitle') || t.infoTestTitle,
|
||||
Message: browser.i18n.getMessage('infoTestMessage') || t.infoTestMessage
|
||||
}
|
||||
},
|
||||
Token: {
|
||||
Header: browser.i18n.getMessage('tokenHeader') || t.tokenHeader,
|
||||
Copy: browser.i18n.getMessage('tokenCopy') || t.tokenCopy,
|
||||
Copied: browser.i18n.getMessage('tokenCopied') || t.tokenCopied,
|
||||
Description: browser.i18n.getMessage('tokenDescription') || t.tokenDescription
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -19,8 +19,7 @@
|
||||
|
||||
import './styles/content_script.scss';
|
||||
const browser = require('webextension-polyfill');
|
||||
const { observe, createObserver } = require('./observer');
|
||||
const { getTabData, getInputs, addInputListener, portSetup, isInFrame, addFormElementsNumber, getFormElements } = require('./functions');
|
||||
const { getTabData, portSetup, isInFrame } = require('./functions');
|
||||
const contentOnMessage = require('./events/contentOnMessage');
|
||||
const { loadFromLocalStorage, saveToLocalStorage } = require('../localStorage');
|
||||
const storeLog = require('../partials/storeLog');
|
||||
@ -67,14 +66,7 @@ const contentScriptRun = async () => {
|
||||
storage = null;
|
||||
}
|
||||
|
||||
addInputListener(getInputs(), tabData?.id);
|
||||
addFormElementsNumber(getFormElements());
|
||||
|
||||
const mutationObserver = createObserver(tabData);
|
||||
observe(mutationObserver);
|
||||
|
||||
window.addEventListener('beforeunload', async () => {
|
||||
mutationObserver.disconnect();
|
||||
browser.runtime.onMessage.removeListener(onMessageListener);
|
||||
}, { once: true });
|
||||
};
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
const config = require('../../config');
|
||||
const loadFromLocalStorage = require('../../localStorage/loadFromLocalStorage');
|
||||
const { notification, inputToken, getTokenInput, showNotificationInfo, loadFonts, isInFrame, pageLoadComplete } = require('../functions');
|
||||
const { notification, inputToken, getTokenInput, showNotificationInfo, loadFonts, isInFrame, getActiveElement, tokenNotification } = require('../functions');
|
||||
const storeLog = require('../../partials/storeLog');
|
||||
|
||||
const contentOnMessage = async (request, tabData) => {
|
||||
@ -37,20 +37,7 @@ const contentOnMessage = async (request, tabData) => {
|
||||
return storeLog('error', 17, err, 'contentOnMessage loadFromLocalStorage');
|
||||
}
|
||||
|
||||
if (!storage || !storage[`tabData-${tabData?.id}`]) {
|
||||
if (isInFrame()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'notification',
|
||||
title: config.Texts.Warning.SelectInput.Title,
|
||||
message: config.Texts.Warning.SelectInput.Message
|
||||
};
|
||||
}
|
||||
|
||||
if (storage[`tabData-${tabData?.id}`].requestID !== request.token_request_id) {
|
||||
// No matching requestID
|
||||
if (!storage || !storage[`tabData-${tabData?.id}`] || storage[`tabData-${tabData?.id}`].requestID !== request.token_request_id) {
|
||||
if (isInFrame()) {
|
||||
return false;
|
||||
}
|
||||
@ -63,17 +50,25 @@ const contentOnMessage = async (request, tabData) => {
|
||||
}
|
||||
|
||||
const lastFocusedInput = storage[`tabData-${tabData?.id}`].lastFocusedInput;
|
||||
const tokenInput = getTokenInput(lastFocusedInput);
|
||||
let tokenInput;
|
||||
|
||||
if (!tokenInput) {
|
||||
return { status: 'elementNotFound' };
|
||||
if (lastFocusedInput) {
|
||||
tokenInput = getTokenInput(lastFocusedInput);
|
||||
}
|
||||
|
||||
if (!lastFocusedInput || !tokenInput) {
|
||||
return tokenNotification(request.token);
|
||||
} else {
|
||||
return inputToken(request, tokenInput, tabData?.url);
|
||||
}
|
||||
}
|
||||
|
||||
return inputToken(request, tokenInput, tabData?.url);
|
||||
case 'getActiveElement': {
|
||||
return getActiveElement();
|
||||
}
|
||||
|
||||
case 'pageLoadComplete': {
|
||||
return pageLoadComplete(tabData?.id);
|
||||
return { status: 'ok' }; // Possibly for future use
|
||||
}
|
||||
|
||||
case 'notification':
|
||||
@ -83,7 +78,7 @@ const contentOnMessage = async (request, tabData) => {
|
||||
if (request.action === 'notification') {
|
||||
return notification(request);
|
||||
} else if (request.action === 'notificationInfo') {
|
||||
return showNotificationInfo(request);
|
||||
return showNotificationInfo();
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -17,28 +17,27 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const updateEventListener = (input, func) => {
|
||||
const removeListener = () => {
|
||||
if (typeof input.removeEventListener === 'function') {
|
||||
input.removeEventListener('focus', func);
|
||||
const { loadFromLocalStorage, saveToLocalStorage } = require('../../localStorage')
|
||||
|
||||
const clearAfterInputToken = (inputElement, tabID) => {
|
||||
// CLEAR INPUT
|
||||
if (inputElement) {
|
||||
if (typeof inputElement?.removeAttribute === 'function') {
|
||||
inputElement.removeAttribute('data-twofas-input');
|
||||
}
|
||||
};
|
||||
|
||||
removeListener();
|
||||
|
||||
if (typeof input.addEventListener === 'function') {
|
||||
input.addEventListener('focus', func);
|
||||
}
|
||||
|
||||
if (input && input?.dataset) {
|
||||
input.dataset.twofasInputListener = 'true';
|
||||
}
|
||||
// CLEAR STORAGE
|
||||
return loadFromLocalStorage([`tabData-${tabID}`])
|
||||
.then(storage => {
|
||||
if (storage[`tabData-${tabID}`] && storage[`tabData-${tabID}`].lastFocusedInput) {
|
||||
delete storage[`tabData-${tabID}`].lastFocusedInput;
|
||||
return saveToLocalStorage({ [`tabData-${tabID}`]: storage[`tabData-${tabID}`] });
|
||||
}
|
||||
|
||||
if (input === document.activeElement || input.matches(':focus')) {
|
||||
func({ target: input });
|
||||
}
|
||||
|
||||
window.addEventListener('onbeforeunload', removeListener, { once: true });
|
||||
return true;
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
module.exports = updateEventListener;
|
||||
module.exports = clearAfterInputToken;
|
@ -17,14 +17,38 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const addInputListener = require('../functions/addInputListener');
|
||||
const getInputs = require('../functions/getInputs');
|
||||
const addFormElementsNumber = require('../functions/addFormElementsNumber');
|
||||
const getFormElements = require('../functions/getFormElements');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const clearFormElementsNumber = require('./clearFormElementsNumber');
|
||||
const addFormElementsNumber = require('./addFormElementsNumber');
|
||||
const getFormElements = require('./getFormElements');
|
||||
|
||||
const pageLoadComplete = async tabID => {
|
||||
addInputListener(getInputs(), tabID);
|
||||
const getActiveElement = () => {
|
||||
const activeElement = document.activeElement;
|
||||
let nodeName;
|
||||
|
||||
if (activeElement) {
|
||||
nodeName = activeElement.nodeName.toLowerCase();
|
||||
}
|
||||
|
||||
if (!activeElement || (nodeName !== 'input' && nodeName !== 'textarea')) {
|
||||
return {
|
||||
status: 'activeElement',
|
||||
nodeName,
|
||||
id: null
|
||||
};
|
||||
}
|
||||
|
||||
const inputUUID = uuidv4();
|
||||
activeElement.setAttribute('data-twofas-input', inputUUID);
|
||||
|
||||
clearFormElementsNumber();
|
||||
addFormElementsNumber(getFormElements());
|
||||
|
||||
return {
|
||||
status: 'activeElement',
|
||||
nodeName,
|
||||
id: inputUUID
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = pageLoadComplete;
|
||||
module.exports = getActiveElement;
|
@ -1,27 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const inputsSelectors = require('../../partials/inputsSelectors')();
|
||||
|
||||
const getInputs = node => {
|
||||
const el = node || document;
|
||||
return Array.from(el.querySelectorAll(inputsSelectors));
|
||||
};
|
||||
|
||||
module.exports = getInputs;
|
@ -18,24 +18,21 @@
|
||||
//
|
||||
|
||||
exports.addFormElementsNumber = require('./addFormElementsNumber');
|
||||
exports.addInputListener = require('./addInputListener');
|
||||
exports.clearAfterInputToken = require('./clearAfterInputToken');
|
||||
exports.clearFormElementsNumber = require('./clearFormElementsNumber');
|
||||
exports.clickSubmit = require('./clickSubmit');
|
||||
exports.closeNotificationInfo = require('./closeNotificationInfo');
|
||||
exports.getActiveElement = require('./getActiveElement');
|
||||
exports.getFormElements = require('./getFormElements');
|
||||
exports.getFormSubmitElements = require('./getFormSubmitElements');
|
||||
exports.getInputs = require('./getInputs');
|
||||
exports.getTabData = require('./getTabData');
|
||||
exports.getTokenInput = require('./getTokenInput');
|
||||
exports.inputFocus = require('./inputFocus');
|
||||
exports.inputToken = require('./inputToken');
|
||||
exports.isInFrame = require('./isInFrame');
|
||||
exports.isVisible = require('./isVisible');
|
||||
exports.loadFonts = require('./loadFonts');
|
||||
exports.neverShowNotificationInfo = require('./neverShowNotificationInfo');
|
||||
exports.notification = require('./notification');
|
||||
exports.openOptionsPage = require('./openOptionsPage');
|
||||
exports.pageLoadComplete = require('./pageLoadComplete');
|
||||
exports.portSetup = require('./portSetup');
|
||||
exports.showNotificationInfo = require('./showNotificationInfo');
|
||||
exports.updateEventListener = require('./updateEventListener');
|
||||
exports.tokenNotification = require('./tokenNotification');
|
||||
|
@ -1,61 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const browser = require('webextension-polyfill');
|
||||
const { loadFromLocalStorage, saveToLocalStorage } = require('../../localStorage');
|
||||
const storeLog = require('../../partials/storeLog');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
const inputFocus = async (event, tabID) => {
|
||||
if (!browser?.runtime?.id || !event || !event?.target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let storage;
|
||||
const el = event.target;
|
||||
|
||||
try {
|
||||
storage = await loadFromLocalStorage([`tabData-${tabID}`]);
|
||||
} catch (err) {
|
||||
return storeLog('error', 16, err, 'inputFocus - no URL/tabID');
|
||||
}
|
||||
|
||||
try {
|
||||
const tabData = storage[`tabData-${tabID}`] ? storage[`tabData-${tabID}`] : {};
|
||||
|
||||
if (
|
||||
el?.dataset?.twofasInput?.length > 0 &&
|
||||
(typeof el?.dataset?.twofasInput === 'string' || el?.dataset?.twofasInput instanceof String)
|
||||
) {
|
||||
tabData.lastFocusedInput = el.dataset.twofasInput;
|
||||
} else {
|
||||
if (typeof el?.setAttribute === 'function') {
|
||||
const inputUUID = uuidv4();
|
||||
el.setAttribute('data-twofas-input', inputUUID);
|
||||
tabData.lastFocusedInput = inputUUID;
|
||||
}
|
||||
}
|
||||
|
||||
return saveToLocalStorage({ [`tabData-${tabID}`]: tabData }, storage);
|
||||
} catch (err) {
|
||||
return storeLog('error', 16, err, storage[`tabData-${tabID}`]?.url);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = inputFocus;
|
@ -21,6 +21,7 @@
|
||||
const delay = require('../../partials/delay');
|
||||
const getTabData = require('./getTabData');
|
||||
const clickSubmit = require('./clickSubmit');
|
||||
const clearAfterInputToken = require('./clearAfterInputToken');
|
||||
|
||||
const inputToken = (request, inputElement, siteURL) => {
|
||||
return new Promise(resolve => {
|
||||
@ -81,6 +82,8 @@ const inputToken = (request, inputElement, siteURL) => {
|
||||
clickSubmit(inputElement, siteURL);
|
||||
}
|
||||
|
||||
clearAfterInputToken(inputElement, tab.id);
|
||||
|
||||
return resolve({
|
||||
status: 'completed',
|
||||
url: siteURL
|
||||
|
@ -1,32 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
/* global IntersectionObserver */
|
||||
const isVisible = domElement => {
|
||||
return new Promise(resolve => {
|
||||
const o = new IntersectionObserver(([entry]) => {
|
||||
resolve(entry.intersectionRatio === 1);
|
||||
o.disconnect();
|
||||
});
|
||||
|
||||
o.observe(domElement);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = isVisible;
|
@ -69,21 +69,30 @@ const notification = request => {
|
||||
setTimeout(() => n.notification.classList.add('visible'), 300);
|
||||
|
||||
window.addEventListener('beforeunload', () => {
|
||||
n.notification.classList.remove('visible');
|
||||
if (n && n.notification) {
|
||||
n.notification.classList.remove('visible');
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
n.notification.classList.add('hidden');
|
||||
n = null;
|
||||
if (n && n.notification) {
|
||||
n.notification.classList.add('hidden');
|
||||
n = null;
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
|
||||
if (request.timeout) {
|
||||
setTimeout(() => {
|
||||
n.notification.classList.remove('visible');
|
||||
if (n && n.notification) {
|
||||
n.notification.classList.remove('visible');
|
||||
}
|
||||
}, 5300);
|
||||
|
||||
setTimeout(() => {
|
||||
n.notification.classList.add('hidden');
|
||||
n = null;
|
||||
if (n && n.notification) {
|
||||
n.notification.classList.add('hidden');
|
||||
n = null;
|
||||
}
|
||||
}, 5600);
|
||||
}
|
||||
};
|
||||
|
146
src/content/functions/tokenNotification.js
Normal file
146
src/content/functions/tokenNotification.js
Normal file
@ -0,0 +1,146 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const config = require('../../config');
|
||||
const isInFrame = require('./isInFrame');
|
||||
const { createElement, createSVGElement, createTextElement } = require('../../partials/DOMElements');
|
||||
const iconSrc = require('../../images/notification-logo.svg');
|
||||
const copySrc = require('../../images/copy-icon.svg');
|
||||
const closeSrc = require('../../images/notification-close.svg');
|
||||
const S = require('../../selectors');
|
||||
|
||||
const tokenNotification = token => {
|
||||
if (isInFrame()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let n = {
|
||||
container: document.querySelector(S.notification.container),
|
||||
notification: null,
|
||||
firstCol: null,
|
||||
logo: null,
|
||||
secondCol: null,
|
||||
header: null,
|
||||
h3: null,
|
||||
tokenBox: null,
|
||||
tokenText: null,
|
||||
tokenIconContainer: null,
|
||||
tokenIcon: null,
|
||||
tokenButton: null,
|
||||
tokenButtonText: null,
|
||||
notificationText: null,
|
||||
p: null,
|
||||
closeBtn: null,
|
||||
close: null
|
||||
};
|
||||
|
||||
const closeNotification = e => {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
if (n && n.notification) {
|
||||
n.notification.classList.remove('visible');
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (n && n.notification) {
|
||||
n.notification.classList.add('hidden');
|
||||
n = null;
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
|
||||
if (!n.container) {
|
||||
n.container = createElement('div', 'twofas-be-notifications');
|
||||
window.top.document.body.appendChild(n.container);
|
||||
}
|
||||
|
||||
n.notification = createElement('div', 'twofas-be-notification');
|
||||
n.closeBtn = createElement('button', 'twofas-be-notification-close');
|
||||
n.closeBtn.addEventListener('click', closeNotification);
|
||||
n.close = createSVGElement(closeSrc);
|
||||
n.closeBtn.appendChild(n.close);
|
||||
n.notification.appendChild(n.closeBtn);
|
||||
|
||||
n.firstCol = createElement('div', 'twofas-be-col');
|
||||
n.logo = createSVGElement(iconSrc);
|
||||
|
||||
n.firstCol.appendChild(n.logo);
|
||||
n.notification.appendChild(n.firstCol);
|
||||
|
||||
n.secondCol = createElement('div', 'twofas-be-col');
|
||||
n.header = createElement('div', 'twofas-be-notification-header');
|
||||
n.h3 = createTextElement('h3', config.Texts.Token.Header);
|
||||
|
||||
n.header.appendChild(n.h3);
|
||||
n.secondCol.appendChild(n.header);
|
||||
|
||||
n.tokenBox = createElement('div', 'twofas-be-notification-token-box');
|
||||
n.tokenText = createTextElement('p', token, 'twofas-be-notification-token-box-text');
|
||||
n.tokenButton = createElement('button', 'twofas-be-notification-token-box-copy-button');
|
||||
n.tokenButton.addEventListener('click', () => {
|
||||
navigator.clipboard.writeText(token);
|
||||
n.tokenButtonText.innerText = config.Texts.Token.Copied;
|
||||
|
||||
setTimeout(() => {
|
||||
n.tokenButtonText.innerText = config.Texts.Token.Copy;
|
||||
}, 1000);
|
||||
});
|
||||
n.tokenButtonText = createTextElement('span', config.Texts.Token.Copy);
|
||||
n.tokenIconContainer = createElement('div', 'twofas-be-notification-token-box-copy-icon');
|
||||
n.tokenIcon = createSVGElement(copySrc);
|
||||
|
||||
n.tokenButton.appendChild(n.tokenButtonText);
|
||||
n.tokenIconContainer.appendChild(n.tokenIcon);
|
||||
n.tokenButton.appendChild(n.tokenIconContainer);
|
||||
n.tokenBox.appendChild(n.tokenText);
|
||||
n.tokenBox.appendChild(n.tokenButton);
|
||||
n.secondCol.appendChild(n.tokenBox);
|
||||
|
||||
n.notificationText = createElement('div', 'twofas-be-notification-text');
|
||||
n.p = createTextElement('p', config.Texts.Token.Description);
|
||||
|
||||
n.notificationText.appendChild(n.p);
|
||||
n.secondCol.appendChild(n.notificationText);
|
||||
n.notification.appendChild(n.secondCol);
|
||||
n.container.appendChild(n.notification);
|
||||
|
||||
setTimeout(() => n.notification.classList.add('visible'), 300);
|
||||
|
||||
window.addEventListener('beforeunload', () => {
|
||||
closeNotification();
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
if (n && n.notification) {
|
||||
n.notification.classList.remove('visible');
|
||||
}
|
||||
}, 30300);
|
||||
|
||||
setTimeout(() => {
|
||||
if (n && n.notification) {
|
||||
n.notification.classList.add('hidden');
|
||||
n = null;
|
||||
}
|
||||
}, 30600);
|
||||
};
|
||||
|
||||
module.exports = tokenNotification;
|
@ -1,65 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
/* global MutationObserver, HTMLElement */
|
||||
const addedNodes = require('./observerFunctions/addedNodes');
|
||||
const hiddenNodes = require('./observerFunctions/hiddenNodes');
|
||||
const removedNodes = require('./observerFunctions/removedNodes');
|
||||
const notObservedNodes = require('./observerConstants/notObservedNodes');
|
||||
const notObservedAttributes = require('./observerConstants/notObservedAttributes');
|
||||
|
||||
const createObserver = tabData => {
|
||||
return new MutationObserver(mutations => {
|
||||
if (!mutations) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mutations.forEach(async mutation => {
|
||||
const mutationNodeName = mutation.target.nodeName.toLowerCase();
|
||||
|
||||
if (
|
||||
!mutation ||
|
||||
!(mutation?.target instanceof HTMLElement) ||
|
||||
mutation?.target?.classList?.contains('twofas-be-notification') ||
|
||||
notObservedAttributes.includes(mutation?.attributeName) ||
|
||||
notObservedNodes.includes(mutationNodeName)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
(mutation?.addedNodes && Array.from(mutation?.addedNodes).length > 0) ||
|
||||
(mutation?.attributeName === 'disabled' && !mutation?.target?.disabled) ||
|
||||
(mutation?.attributeName === 'style' && mutation?.target)
|
||||
) {
|
||||
addedNodes(mutation, tabData);
|
||||
}
|
||||
|
||||
if (mutation?.type === 'attributes' && mutation?.target) {
|
||||
hiddenNodes(mutation, tabData);
|
||||
}
|
||||
|
||||
if (mutation?.removedNodes && Array.from(mutation?.removedNodes).length > 0) {
|
||||
removedNodes(mutation, tabData);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = createObserver;
|
@ -1,21 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
exports.createObserver = require('./createObserver');
|
||||
exports.observe = require('./observe');
|
@ -1,33 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const observe = mutationObserver => {
|
||||
const el = document?.body || document;
|
||||
|
||||
return mutationObserver.observe(el, {
|
||||
attributes: true,
|
||||
characterData: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributeOldValue: false,
|
||||
characterDataOldValue: false
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = observe;
|
@ -1,23 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
exports.notObservedAttributes = require('./notObservedAttributes');
|
||||
exports.notObservedNodes = require('./notObservedNodes');
|
||||
exports.significantNodes = require('./significantNodes');
|
||||
exports.significantInputs = require('./significantInputs');
|
@ -1,132 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const notObservedAttributes = [
|
||||
// 2FAS
|
||||
'data-twofas-element-number',
|
||||
'data-twofas-input-listener',
|
||||
// CUSTOM
|
||||
'data-ng-animate',
|
||||
'data-submitting',
|
||||
// GLOBAL ATTRIBUTES
|
||||
'href',
|
||||
'acceskey',
|
||||
'autocapitalize',
|
||||
'contenteditable',
|
||||
'dir',
|
||||
'draggable',
|
||||
'enterkeyhint',
|
||||
'exportsparts',
|
||||
'inert',
|
||||
'inputmode',
|
||||
'is',
|
||||
'itemid',
|
||||
'itemprop',
|
||||
'itemref',
|
||||
'itemscope',
|
||||
'itemtype',
|
||||
'lang',
|
||||
'nonce',
|
||||
'part',
|
||||
'popover',
|
||||
'slot',
|
||||
'spellcheck',
|
||||
'tabindex',
|
||||
'title',
|
||||
'translate',
|
||||
'virtualkeyboardpolicy',
|
||||
'role',
|
||||
'accept',
|
||||
'autocomplete',
|
||||
'autocorrect',
|
||||
'capture',
|
||||
'crossorigin',
|
||||
'dirname',
|
||||
'elementtiming',
|
||||
'for',
|
||||
'max',
|
||||
'maxlength',
|
||||
'min',
|
||||
'minlength',
|
||||
'multiple',
|
||||
'pattern',
|
||||
'placeholder',
|
||||
'readonly',
|
||||
'rel',
|
||||
'required',
|
||||
'size',
|
||||
'step',
|
||||
// ARIA
|
||||
'aria-activedescendant',
|
||||
'aria-atomic',
|
||||
'aria-autocomplete',
|
||||
'aria-braillelabel',
|
||||
'aria-brailleroledescription',
|
||||
'aria-busy',
|
||||
'aria-checked',
|
||||
'aria-colcount',
|
||||
'aria-colindex',
|
||||
'aria-colindextext',
|
||||
'aria-colspan',
|
||||
'aria-controls',
|
||||
'aria-current',
|
||||
'aria-describedby',
|
||||
'aria-description',
|
||||
'aria-details',
|
||||
'aria-disabled',
|
||||
'aria-dropeffect',
|
||||
'aria-errormessage',
|
||||
'aria-expanded',
|
||||
'aria-flowto',
|
||||
'aria-grabbed',
|
||||
'aria-haspopup',
|
||||
'aria-hidden',
|
||||
'aria-invalid',
|
||||
'aria-keyshortcuts',
|
||||
'aria-label',
|
||||
'aria-labelledby',
|
||||
'aria-level',
|
||||
'aria-live',
|
||||
'aria-modal',
|
||||
'aria-multiline',
|
||||
'aria-multiselectable',
|
||||
'aria-orientation',
|
||||
'aria-owns',
|
||||
'aria-placeholder',
|
||||
'aria-posinset',
|
||||
'aria-pressed',
|
||||
'aria-readonly',
|
||||
'aria-relevant',
|
||||
'aria-required',
|
||||
'aria-roledescription',
|
||||
'aria-rowcount',
|
||||
'aria-rowindex',
|
||||
'aria-rowindextext',
|
||||
'aria-rowspan',
|
||||
'aria-selected',
|
||||
'aria-setsize',
|
||||
'aria-sort',
|
||||
'aria-valuemax',
|
||||
'aria-valuemin',
|
||||
'aria-valuenow',
|
||||
'aria-valuetext',
|
||||
'value'
|
||||
];
|
||||
|
||||
module.exports = notObservedAttributes;
|
@ -1,105 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const notObservedNodes = [
|
||||
'a',
|
||||
'g',
|
||||
'path',
|
||||
'html',
|
||||
'body',
|
||||
'head',
|
||||
'link',
|
||||
'style',
|
||||
'script',
|
||||
'noscript',
|
||||
'title',
|
||||
'#cdata-section',
|
||||
'#comment',
|
||||
'#text',
|
||||
'abbr',
|
||||
'address',
|
||||
'area',
|
||||
'audio',
|
||||
'b',
|
||||
'base',
|
||||
'bdi',
|
||||
'bdo',
|
||||
'blockquote',
|
||||
'br',
|
||||
'button',
|
||||
'canvas',
|
||||
'caption',
|
||||
'cite',
|
||||
'code',
|
||||
'data',
|
||||
'dd',
|
||||
'del',
|
||||
'details',
|
||||
'dfn',
|
||||
'dialog',
|
||||
'dl',
|
||||
'dt',
|
||||
'em',
|
||||
'embed',
|
||||
'figure',
|
||||
'hr',
|
||||
'i',
|
||||
'img',
|
||||
'ins',
|
||||
'label',
|
||||
'legend',
|
||||
'map',
|
||||
'mark',
|
||||
'meta',
|
||||
'meter',
|
||||
'object',
|
||||
'optgroup',
|
||||
'option',
|
||||
'output',
|
||||
'param',
|
||||
'picture',
|
||||
'pre',
|
||||
'progress',
|
||||
'q',
|
||||
'rp',
|
||||
'rt',
|
||||
'ruby',
|
||||
's',
|
||||
'samp',
|
||||
'search',
|
||||
'select',
|
||||
'small',
|
||||
'source',
|
||||
'strong',
|
||||
'sub',
|
||||
'sup',
|
||||
'svg',
|
||||
'summary',
|
||||
'template',
|
||||
'time',
|
||||
'track',
|
||||
'u',
|
||||
'var',
|
||||
'video',
|
||||
'wbr',
|
||||
// custom
|
||||
'tool-tip'
|
||||
];
|
||||
|
||||
module.exports = notObservedNodes;
|
@ -1,25 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const significantInputs = [
|
||||
'input',
|
||||
'textarea'
|
||||
];
|
||||
|
||||
module.exports = significantInputs;
|
@ -1,25 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const significantNodes = [
|
||||
'input',
|
||||
'textarea'
|
||||
];
|
||||
|
||||
module.exports = significantNodes;
|
@ -1,101 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const browser = require('webextension-polyfill');
|
||||
const findSignificantChanges = require('./findSignificantChanges');
|
||||
const { getInputs, addInputListener, clearFormElementsNumber, addFormElementsNumber, getFormElements } = require('../../functions');
|
||||
const getChildNodes = require('./getChildNodes');
|
||||
const storeLog = require('../../../partials/storeLog');
|
||||
const notObservedNodes = require('../observerConstants/notObservedNodes');
|
||||
const uniqueOnly = require('../../../partials/uniqueOnly');
|
||||
|
||||
let queue = [];
|
||||
let tabData = null;
|
||||
let timeout;
|
||||
|
||||
const process = nodes => {
|
||||
if (document.readyState !== 'complete') {
|
||||
timeout = window.requestAnimationFrame(() => process(nodes));
|
||||
}
|
||||
|
||||
if (!nodes || nodes.length <= 0 || !tabData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const addedNodes =
|
||||
nodes
|
||||
.filter(uniqueOnly)
|
||||
.filter(node => !notObservedNodes.includes(node.nodeName.toLowerCase()))
|
||||
.flatMap(getChildNodes)
|
||||
.filter(uniqueOnly)
|
||||
.filter(node => !notObservedNodes.includes(node.nodeName.toLowerCase()));
|
||||
|
||||
let newInputs = false;
|
||||
let inputs = [];
|
||||
|
||||
for (const node in addedNodes) {
|
||||
if (findSignificantChanges(addedNodes[node])) {
|
||||
newInputs = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!newInputs) {
|
||||
for (const node in addedNodes) {
|
||||
inputs.push(...getInputs(addedNodes[node]));
|
||||
}
|
||||
|
||||
inputs = inputs.filter(node => !node.hasAttribute('data-twofas-input'));
|
||||
newInputs = inputs.length > 0;
|
||||
} else {
|
||||
inputs = getInputs();
|
||||
}
|
||||
|
||||
if (newInputs) {
|
||||
try {
|
||||
addInputListener(inputs, tabData?.id);
|
||||
clearFormElementsNumber();
|
||||
addFormElementsNumber(getFormElements());
|
||||
} catch (err) {
|
||||
return storeLog('error', 15, err, tabData?.url);
|
||||
}
|
||||
}
|
||||
|
||||
queue = [];
|
||||
};
|
||||
|
||||
const addedNodes = (mutation, tabInfo) => {
|
||||
if (!mutation?.target || !browser?.runtime?.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
queue.push(mutation.target);
|
||||
queue.push(...Array.from(mutation.addedNodes));
|
||||
|
||||
if (!tabData) {
|
||||
tabData = tabInfo;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
window.cancelAnimationFrame(timeout);
|
||||
}
|
||||
|
||||
timeout = window.requestAnimationFrame(() => process(queue));
|
||||
};
|
||||
|
||||
module.exports = addedNodes;
|
@ -1,26 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const significantNodes = require('../observerConstants/significantNodes');
|
||||
|
||||
const findSignificantChanges = node => {
|
||||
return significantNodes.includes(node.nodeName.toLowerCase());
|
||||
};
|
||||
|
||||
module.exports = findSignificantChanges;
|
@ -1,101 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const browser = require('webextension-polyfill');
|
||||
const isVisible = require('../../functions/isVisible');
|
||||
const findSignificantChanges = require('./findSignificantChanges');
|
||||
const getChildNodes = require('./getChildNodes');
|
||||
const { loadFromLocalStorage, saveToLocalStorage } = require('../../../localStorage');
|
||||
const storeLog = require('../../../partials/storeLog');
|
||||
const { clearFormElementsNumber, addFormElementsNumber, getFormElements } = require('../../functions');
|
||||
const uniqueOnly = require('../../../partials/uniqueOnly');
|
||||
|
||||
let queue = [];
|
||||
let tabData = null;
|
||||
let timeout;
|
||||
|
||||
const process = async nodes => {
|
||||
if (document.readyState !== 'complete') {
|
||||
timeout = window.requestAnimationFrame(() => process(nodes));
|
||||
}
|
||||
|
||||
if (!nodes || nodes.length <= 0 || !tabData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hiddenNodes =
|
||||
nodes
|
||||
.filter(uniqueOnly)
|
||||
.filter(node => findSignificantChanges(node) && node.getAttribute('data-twofas-input'))
|
||||
.flatMap(getChildNodes)
|
||||
.filter(uniqueOnly)
|
||||
.filter(node => findSignificantChanges(node) && node.getAttribute('data-twofas-input'));
|
||||
|
||||
let storage;
|
||||
|
||||
clearFormElementsNumber();
|
||||
addFormElementsNumber(getFormElements());
|
||||
|
||||
try {
|
||||
storage = await loadFromLocalStorage([`tabData-${tabData?.id}`]);
|
||||
} catch (err) {
|
||||
return storeLog('error', 41, err, tabData?.url);
|
||||
}
|
||||
|
||||
if (!storage[`tabData-${tabData?.id}`] || !storage[`tabData-${tabData?.id}`].lastFocusedInput) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hiddenNodes.forEach(async node => {
|
||||
const visible = await isVisible(node);
|
||||
|
||||
if (node.getAttribute('data-twofas-input') === storage[`tabData-${tabData?.id}`].lastFocusedInput && !visible) {
|
||||
delete storage[`tabData-${tabData?.id}`].lastFocusedInput;
|
||||
|
||||
if (document?.activeElement && document?.activeElement?.getAttribute('data-twofas-input')) {
|
||||
storage[`tabData-${tabData?.id}`].lastFocusedInput = document.activeElement.getAttribute('data-twofas-input');
|
||||
}
|
||||
|
||||
return saveToLocalStorage({ [`tabData-${tabData?.id}`]: storage[`tabData-${tabData?.id}`] })
|
||||
.catch(err => storeLog('error', 42, err, tabData?.url));
|
||||
}
|
||||
|
||||
queue = [];
|
||||
});
|
||||
};
|
||||
|
||||
const hiddenNodes = (mutation, tabInfo) => {
|
||||
if (!mutation?.target || !browser?.runtime?.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
queue.push(mutation.target);
|
||||
|
||||
if (!tabData) {
|
||||
tabData = tabInfo;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
window.cancelAnimationFrame(timeout);
|
||||
}
|
||||
|
||||
timeout = window.requestAnimationFrame(() => process(queue));
|
||||
};
|
||||
|
||||
module.exports = hiddenNodes;
|
@ -1,23 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
exports.addedNodes = require('./addedNodes');
|
||||
exports.getChildNodes = require('./getChildNodes');
|
||||
exports.hiddenNodes = require('./hiddenNodes');
|
||||
exports.removedNodes = require('./removedNodes');
|
@ -1,113 +0,0 @@
|
||||
//
|
||||
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
|
||||
// Copyright © 2023 Two Factor Authentication Service, Inc.
|
||||
// Contributed by Grzegorz Zając. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
const browser = require('webextension-polyfill');
|
||||
const significantInputs = require('../observerConstants/significantInputs');
|
||||
const { loadFromLocalStorage, saveToLocalStorage } = require('../../../localStorage');
|
||||
const getChildNodes = require('./getChildNodes');
|
||||
const storeLog = require('../../../partials/storeLog');
|
||||
const { clearFormElementsNumber, addFormElementsNumber, getFormElements } = require('../../functions');
|
||||
const notObservedNodes = require('../observerConstants/notObservedNodes');
|
||||
const uniqueOnly = require('../../../partials/uniqueOnly');
|
||||
|
||||
let queue = [];
|
||||
let tabData = null;
|
||||
let timeout;
|
||||
|
||||
const process = async nodes => {
|
||||
if (document.readyState !== 'complete') {
|
||||
timeout = window.requestAnimationFrame(() => process(nodes));
|
||||
}
|
||||
|
||||
if (!nodes || nodes.length <= 0 || !tabData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ids = [];
|
||||
let storage;
|
||||
|
||||
const removedNodes =
|
||||
nodes
|
||||
.filter(uniqueOnly)
|
||||
.filter(node => !notObservedNodes.includes(node.nodeName.toLowerCase()))
|
||||
.flatMap(getChildNodes)
|
||||
.filter(uniqueOnly)
|
||||
.filter(node => !notObservedNodes.includes(node.nodeName.toLowerCase()));
|
||||
|
||||
removedNodes.forEach(node => {
|
||||
const nodeName = node.nodeName.toLowerCase();
|
||||
|
||||
if (!significantInputs.includes(nodeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const twofasInput = node.getAttribute('data-twofas-input');
|
||||
|
||||
if (twofasInput) {
|
||||
ids.push(twofasInput);
|
||||
}
|
||||
});
|
||||
|
||||
queue = [];
|
||||
|
||||
if (ids.length <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clearFormElementsNumber();
|
||||
addFormElementsNumber(getFormElements());
|
||||
|
||||
try {
|
||||
storage = await loadFromLocalStorage([`tabData-${tabData?.id}`]);
|
||||
} catch (err) {
|
||||
return storeLog('error', 39, err, tabData?.url);
|
||||
}
|
||||
|
||||
if (!storage[`tabData-${tabData?.id}`] || !storage[`tabData-${tabData?.id}`].lastFocusedInput) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ids.includes(storage[`tabData-${tabData?.id}`].lastFocusedInput)) {
|
||||
delete storage[`tabData-${tabData?.id}`].lastFocusedInput;
|
||||
}
|
||||
|
||||
return saveToLocalStorage({ [`tabData-${tabData?.id}`]: storage[`tabData-${tabData?.id}`] })
|
||||
.catch(err => storeLog('error', 40, err, tabData?.url));
|
||||
};
|
||||
|
||||
const removedNodes = (mutation, tabInfo) => {
|
||||
if (!mutation?.target || !browser?.runtime?.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
queue.push(mutation.target);
|
||||
queue.push(...Array.from(mutation.removedNodes));
|
||||
|
||||
if (!tabData) {
|
||||
tabData = tabInfo;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
window.cancelAnimationFrame(timeout);
|
||||
}
|
||||
|
||||
timeout = window.requestAnimationFrame(() => process(queue));
|
||||
};
|
||||
|
||||
module.exports = removedNodes;
|
@ -33,6 +33,7 @@
|
||||
top: 25px !important;
|
||||
user-select: none !important;
|
||||
z-index: 999999 !important;
|
||||
z-index: infinite !important;
|
||||
|
||||
@media all and (max-width: 400px) {
|
||||
padding: 10px !important;
|
||||
@ -56,9 +57,12 @@
|
||||
margin-bottom: 25px !important;
|
||||
max-width: 380px !important;
|
||||
overflow: hidden !important;
|
||||
position: relative !important;
|
||||
text-align: left !important;
|
||||
transform: translateX(425px) !important;
|
||||
transition: box-shadow .3s ease-in-out, max-height .3s ease-in-out, margin-bottom .3s ease-in-out, transform .3s ease-in-out !important;
|
||||
z-index: 999999 !important;
|
||||
z-index: infinite !important;
|
||||
|
||||
&.visible {
|
||||
box-shadow: 0 0 20px 5px $shadow-color !important;
|
||||
@ -70,6 +74,24 @@
|
||||
max-height: 0 !important;
|
||||
}
|
||||
|
||||
&-close {
|
||||
appearance: none !important;
|
||||
background: transparent !important;
|
||||
border: 0 !important;
|
||||
cursor: pointer !important;
|
||||
padding: 0 !important;
|
||||
position: absolute !important;
|
||||
right: 2px !important;
|
||||
top: 2px !important;
|
||||
|
||||
> svg {
|
||||
height: auto !important;
|
||||
margin-right: 0 !important;
|
||||
max-width: unset !important;
|
||||
width: 24px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-buttons {
|
||||
border-radius: 0 !important;
|
||||
box-shadow: none !important;
|
||||
@ -120,6 +142,84 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-token-box {
|
||||
align-items: center !important;
|
||||
display: flex !important;
|
||||
flex-direction: row !important;
|
||||
justify-content: space-between !important;
|
||||
margin-bottom: 10px !important;
|
||||
|
||||
> p {
|
||||
&.twofas-be-notification-token-box-text {
|
||||
color: $color !important;
|
||||
font-size: 32px !important;
|
||||
font-weight: 700 !important;
|
||||
|
||||
@media all and (max-width: 400px) {
|
||||
font-size: 24px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> button {
|
||||
&.twofas-be-notification-token-box-copy-button {
|
||||
align-items: center !important;
|
||||
appearance: none !important;
|
||||
background-color: $theme-color !important;
|
||||
border: 0 !important;
|
||||
border-radius: 20px !important;
|
||||
color: $color-2 !important;
|
||||
cursor: pointer !important;
|
||||
display: inline-flex !important;
|
||||
flex-direction: row !important;
|
||||
font-size: 12px !important;
|
||||
font-weight: 600 !important;
|
||||
height: 40px !important;
|
||||
justify-content: space-between !important;
|
||||
letter-spacing: .9px !important;
|
||||
line-height: 40px !important;
|
||||
padding: 0 5px 0 16px !important;
|
||||
outline: none !important;
|
||||
text-align: center !important;
|
||||
text-decoration: none !important;
|
||||
text-transform: uppercase !important;
|
||||
transition: background-color .2s ease-in-out, color .2s ease-in-out !important;
|
||||
|
||||
&:hover {
|
||||
background-color: color.adjust($theme-color, $lightness: -10%) !important;
|
||||
color: $color-2 !important;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: color.adjust($theme-color, $lightness: -20%) !important;
|
||||
color: $color-2 !important;
|
||||
}
|
||||
|
||||
> span {
|
||||
flex-grow: 1 !important;
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
|
||||
> .twofas-be-notification-token-box-copy-icon {
|
||||
align-items: center !important;
|
||||
background-color: $color-2 !important;
|
||||
border-radius: 50% !important;
|
||||
display: flex !important;
|
||||
justify-content: center !important;
|
||||
height: 32px !important;
|
||||
width: 32px !important;
|
||||
|
||||
> svg {
|
||||
height: 16px !important;
|
||||
margin-right: 0 !important;
|
||||
max-width: 100% !important;
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.twofas-be-col {
|
||||
flex-shrink: unset !important;
|
||||
font-family: 'Montserrat', sans-serif !important;
|
||||
@ -134,6 +234,13 @@
|
||||
&:last-of-type {
|
||||
margin-right: 18px !important;
|
||||
}
|
||||
|
||||
> svg {
|
||||
height: 34px !important;
|
||||
margin-right: 16px !important;
|
||||
max-width: 28px !important;
|
||||
width: 28px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ProtonMail FIX */
|
||||
@ -146,13 +253,6 @@
|
||||
}
|
||||
/* ProtonMail FIX */
|
||||
|
||||
svg {
|
||||
height: 34px !important;
|
||||
margin-right: 16px;
|
||||
max-width: 28px !important;
|
||||
width: 28px !important;
|
||||
}
|
||||
|
||||
h3,
|
||||
p {
|
||||
font-family: 'Montserrat', sans-serif !important;
|
||||
|
6
src/images/copy-icon.svg
Normal file
6
src/images/copy-icon.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 21 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="copy">
|
||||
<rect id="Rectangle 2" x="5.74951" y="1.25003" width="14.4997" height="14.4997" rx="1.25" stroke="#ED1C24" stroke-width="1.5"/>
|
||||
<path id="Rectangle 3" d="M1.00049 4.50011V18.4998C1.00049 19.6044 1.89592 20.4998 3.00049 20.4998H17.0002" stroke="#ED1C24" stroke-width="1.5"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 373 B |
4
src/images/notification-close.svg
Normal file
4
src/images/notification-close.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="2.143" height="21.429" rx="1.071" transform="rotate(-45 21.339 -7.324)" fill="#B3B3B3"/>
|
||||
<rect x="26.581" y="11.429" width="2.143" height="21.429" rx="1.071" transform="rotate(45 26.581 11.429)" fill="#B3B3B3"/>
|
||||
</svg>
|
After Width: | Height: | Size: 304 B |
@ -3,7 +3,7 @@
|
||||
"name": "2FAS - Two Factor Authentication",
|
||||
"short_name": "2FAS",
|
||||
"author": "Two Factor Authentication Service, Inc.",
|
||||
"version": "1.6.4",
|
||||
"version": "1.7.0",
|
||||
"description": "__MSG_appDesc__",
|
||||
"default_locale": "en",
|
||||
"icons": {
|
||||
@ -71,7 +71,8 @@
|
||||
"tabs",
|
||||
"storage",
|
||||
"notifications",
|
||||
"contextMenus"
|
||||
"contextMenus",
|
||||
"webNavigation"
|
||||
],
|
||||
"host_permissions": [
|
||||
"*://*.2fas.com/*"
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "2FAS - Two Factor Authentication",
|
||||
"short_name": "2FAS",
|
||||
"author": "Two Factor Authentication Service, Inc.",
|
||||
"version": "1.6.4",
|
||||
"version": "1.7.0",
|
||||
"description": "__MSG_appDesc__",
|
||||
"default_locale": "en",
|
||||
"icons": {
|
||||
@ -71,7 +71,8 @@
|
||||
"tabs",
|
||||
"storage",
|
||||
"notifications",
|
||||
"contextMenus"
|
||||
"contextMenus",
|
||||
"webNavigation"
|
||||
],
|
||||
"host_permissions": [
|
||||
"*://*.2fas.com/*"
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "2FAS - Two Factor Authentication",
|
||||
"short_name": "2FAS",
|
||||
"author": "Two Factor Authentication Service, Inc.",
|
||||
"version": "1.6.4",
|
||||
"version": "1.7.0",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "admin@2fas.com",
|
||||
@ -77,6 +77,7 @@
|
||||
"storage",
|
||||
"notifications",
|
||||
"contextMenus",
|
||||
"webNavigation",
|
||||
"https://*.2fas.com/*",
|
||||
"wss://*.2fas.com/*"
|
||||
],
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "2FAS - Two Factor Authentication",
|
||||
"short_name": "2FAS",
|
||||
"author": "Two Factor Authentication Service, Inc.",
|
||||
"version": "1.6.4",
|
||||
"version": "1.7.0",
|
||||
"description": "__MSG_appDesc__",
|
||||
"default_locale": "en",
|
||||
"icons": {
|
||||
@ -70,7 +70,8 @@
|
||||
"tabs",
|
||||
"storage",
|
||||
"notifications",
|
||||
"contextMenus"
|
||||
"contextMenus",
|
||||
"webNavigation"
|
||||
],
|
||||
"host_permissions": [
|
||||
"*://*.2fas.com/*"
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "2FAS - Two Factor Authentication",
|
||||
"short_name": "2FAS",
|
||||
"author": "Two Factor Authentication Service, Inc.",
|
||||
"version": "1.6.4",
|
||||
"version": "1.7.0",
|
||||
"description": "__MSG_appDesc__",
|
||||
"default_locale": "en",
|
||||
"icons": {
|
||||
@ -77,6 +77,7 @@
|
||||
"storage",
|
||||
"notifications",
|
||||
"contextMenus",
|
||||
"webNavigation",
|
||||
"https://*.2fas.com/*",
|
||||
"wss://*.2fas.com/*"
|
||||
],
|
||||
|
@ -92,9 +92,11 @@ const storeLog = async (level, logID = 0, errObj, url = '') => {
|
||||
(storage?.browserInfo?.browser_name === 'Chrome' && storage?.browserInfo?.browser_version === '107' && logID === 14) ||
|
||||
(storage?.browserInfo?.browser_name === 'Chrome' && storage?.browserInfo?.browser_version === '107.0.0.0' && logID === 14) ||
|
||||
(c?.errorInfo?.message?.includes('FILE_ERROR_NO_SPACE')) ||
|
||||
(c?.status === 407) ||
|
||||
(c?.errorInfo.status === 407) ||
|
||||
(c?.errorInfo?.message?.includes('An unexpected error occurred')) ||
|
||||
(c?.errorInfo?.message?.includes('Refused to run the JavaScript URL'))
|
||||
(c?.errorInfo?.message?.includes('Refused to run the JavaScript URL')) ||
|
||||
(c?.errorInfo?.message?.includes('QuotaExceededError: storage.local API call exceeded its quota limitations')) || // @TODO: future
|
||||
(c?.errorInfo?.statusText?.includes('Proxy Authentication Required'))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ const backgroundProdConfig = {
|
||||
name: 'background',
|
||||
entry: './src/background/background.js',
|
||||
mode: 'production',
|
||||
devtool: 'cheap-module-source-map',
|
||||
target: 'web',
|
||||
node: false,
|
||||
output: {
|
||||
path: path.join(__dirname, '../../public/background'),
|
||||
|
@ -34,8 +34,6 @@ const contentScriptProdConfig = {
|
||||
name: 'contentScriptGlobal',
|
||||
entry: './src/content/content_script.js',
|
||||
mode: 'production',
|
||||
devtool: 'cheap-module-source-map',
|
||||
target: 'web',
|
||||
node: false,
|
||||
output: {
|
||||
path: path.join(__dirname, '../../public/content'),
|
||||
|
@ -39,8 +39,6 @@ const installPageProdConfig = {
|
||||
contentPageStyles: './src/content/styles/content_script.scss'
|
||||
},
|
||||
mode: 'production',
|
||||
devtool: 'cheap-module-source-map',
|
||||
target: 'web',
|
||||
node: false,
|
||||
output: {
|
||||
path: path.join(__dirname, '../../public/installPage'),
|
||||
|
@ -39,8 +39,6 @@ const optionsPageProdConfig = {
|
||||
contentPageStyles: './src/content/styles/content_script.scss'
|
||||
},
|
||||
mode: 'production',
|
||||
devtool: 'cheap-module-source-map',
|
||||
target: 'web',
|
||||
node: false,
|
||||
output: {
|
||||
path: path.join(__dirname, '../../public/optionsPage'),
|
||||
|
@ -116,10 +116,10 @@
|
||||
"errorStorageIntegrityMessage": "Please reinstall browser extension or contact with 2FAS Support on Discord",
|
||||
"warningTooSoonTitle": "Wait a moment",
|
||||
"warningTooSoonMessage": "Please wait DIFF seconds before sending another request.",
|
||||
"warningSelectInputTitle": "Select the text field first",
|
||||
"warningSelectInputMessage": "Select the text field for the 2FA token then click the extension icon or use the chosen shortcut.",
|
||||
"successPushSentTitle": "Push sent",
|
||||
"successPushSentMessage": "Please check your phone and accept your login request.",
|
||||
"successPushSentClipboardTitle": "Push sent",
|
||||
"successPushSentClipboardMessage": "Please check your phone and accept your login request. Copy your token and paste it into the correct input on the website.",
|
||||
"successExtNameUpdatedTitle": "Success",
|
||||
"successExtNameUpdatedMessage": "Extension name updated",
|
||||
"successDeviceDisconnectedTitle": "Success",
|
||||
@ -137,6 +137,8 @@
|
||||
"infoUnsupportedProtocolMessage": "Only HTTP and HTTPS protocols are supported by 2FAS Extension",
|
||||
"infoBrowserActionWithoutTabTitle": "Info",
|
||||
"infoBrowserActionWithoutTabMessage": "Using outside the browser is not supported by 2FAS Extension",
|
||||
"infoCopiedToClipboardTitle": "Successfully copied to clipboard",
|
||||
"infoCopiedToClipboardMessage": "You can now paste the token into the input field",
|
||||
"infoTestTitle": "2FAS Notification",
|
||||
"infoTestMessage": "Hi! This is just a test",
|
||||
"optionsTitle": "2FAS Browser Extension | Options",
|
||||
@ -181,5 +183,9 @@
|
||||
"optionsDomainRequired": "Domain is required",
|
||||
"optionsDomainTooLong": "Domain is too long",
|
||||
"optionsDomainIncorrect": "Domain is not correct",
|
||||
"optionsDomainExists": "Domain exists on excluded list"
|
||||
"optionsDomainExists": "Domain exists on excluded list",
|
||||
"tokenHeader": "Your token",
|
||||
"tokenCopy": "Copy",
|
||||
"tokenCopied": "Copied",
|
||||
"tokenDescription": "Copy the token and paste it in the input field. The token will expire in 30 seconds."
|
||||
}
|
Loading…
Reference in New Issue
Block a user