Skip to content

Commit

Permalink
Webpack + DLL Plugin (#134)
Browse files Browse the repository at this point in the history
* WIP

* WIP

* DLLs working

* package update

* Update manifests, etc

* Unworking, need to compare

* Update packer

* progress on inject.js

* We no longer need jquery!

* update DLL library
  • Loading branch information
subdavis authored Apr 15, 2018
1 parent 50e2cf0 commit 4d856b1
Show file tree
Hide file tree
Showing 27 changed files with 388 additions and 278 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ Tusk requires:
# install dependencies
yarn install

# Build static DLL resources
yarn build-dll

# static reload with file watch
yarn watch

Expand Down
File renamed without changes.
8 changes: 4 additions & 4 deletions background/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function Background(protectedMemory, settings) {
if (message.m == "showMessage") {
chrome.notifications.create({
'type': 'basic',
'iconUrl': '/dist/logo_48.png',
'iconUrl': '/assets/icons/logo_48.png',
'title': 'Tusk',
'message': message.text
}, function(notificationId) {
Expand Down Expand Up @@ -91,7 +91,7 @@ function Background(protectedMemory, settings) {
return;
}
chrome.tabs.executeScript(message.tabId, {
file: "dist/inject.build.js",
file: "build/inject.build.js",
allFrames: true,
runAt: "document_start"
}, function(result) {
Expand Down Expand Up @@ -157,7 +157,7 @@ function Background(protectedMemory, settings) {
clearClipboard();
chrome.notifications.create({
'type': 'basic',
'iconUrl': 'dist/logo_48.png',
'iconUrl': '/assets/icons/logo_48.png',
'title': 'Tusk',
'message': 'Clipboard cleared'
}, function(notificationId) {
Expand All @@ -171,7 +171,7 @@ function Background(protectedMemory, settings) {
forgetPassword().then(function() {
chrome.notifications.create({
'type': 'basic',
'iconUrl': 'dist/logo_48.png',
'iconUrl': '/assets/icons/logo_48.png',
'title': 'Tusk',
'message': 'Remembered password expired'
}, function(notificationId) {
Expand Down
73 changes: 38 additions & 35 deletions background/inject.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
let $ = require('jquery')
import { isVisible } from '$lib/utils.js'
/*
Inject script
- Invoked when Tusk popup 'autofill' action is selected.
- Background will attempt to inject this script into the page, and the script will listen for a user/pass combo from background.
*/
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
"use strict";

Expand Down Expand Up @@ -70,39 +75,42 @@ var filler = (function() {
lonelyPasswords = [];
priorityPair = null;
var inputPattern = "input[type='text'], input[type='email'], input[type='password'], input:not([type])";
var inputList = Array.from(document.getElementsByTagName('INPUT'));

//algorithm 1 - based on focused field
var focusedField = $(inputPattern).filter(':focus');
if (focusedField.length) {
// Method 1 - based on focused field (the thing your cursor is in)
var activeElem = document.activeElement
var focusedIndex = inputList.indexOf(activeElem)
if (inputList.length && focusedIndex >= 0) {
var pair = {}, focusedPassword = false;
if (isPasswordField(focusedField)) {
pair.p = focusedField;
if (isPasswordField(activeElem)) {
pair.p = activeElem;
focusedPassword = true;
} else {
pair.u = focusedField;
pair.u = activeElem;
}

var all = $(inputPattern);
var focusedIndex = all.index(focusedField);
if (focusedIndex > -1 && focusedIndex < all.length) {
// Assumption:
// * username will always come before password
// * username and password will always be adjacent
if (focusedIndex >= 0) {
if (focusedPassword && focusedIndex > 0) {
//field before the password is the username
pair.u = all.eq(focusedIndex - 1);
} else if (!focusedPassword && focusedIndex < all.length) {
pair.u = inputList[focusedIndex - 1]
} else if (!focusedPassword && focusedIndex < (inputList.length - 1)) {
//field after the username is the password
pair.p = all.eq(focusedIndex + 1);
let passwordFieldCandidate = inputList[focusedIndex + 1]
if (isPasswordField(passwordFieldCandidate))
pair.p = passwordFieldCandidate
}
}

priorityPair = pair;
}

//algorithm 2 - based on types of fields and visibility
// Methods 2 - based on types of fields and visibility
var possibleUserName;
var lastFieldWasPassword = false; //used to detect registration forms which have 2 password fields, one after the other
$(inputPattern).each(function() {
var field = $(this);
if (isElementInViewport(field) && field.is(':visible')) {
inputList.forEach(field => {
if (isElementInViewport(field) && isVisible(field)) {
if (isPasswordField(field)) {
if (possibleUserName) {
userPasswordPairs.push({
Expand All @@ -129,9 +137,9 @@ var filler = (function() {
}

function isPasswordField(field) {
if (field.attr('type') && field.attr('type').toLowerCase() == 'password')
let type_attr = field.getAttribute('type')
if (type_attr && type_attr.toLowerCase() == 'password')
return true;

return false;
}

Expand All @@ -141,10 +149,10 @@ var filler = (function() {

if (priorityPair) {
//don't bother with the others, this is the one
if (priorityPair.u && priorityPair.u.is(':visible'))
if (priorityPair.u && isVisible(priorityPair.u))
fillField(priorityPair.u, username);

if (priorityPair.p && priorityPair.p.is(':visible'))
if (priorityPair.p && isVisible(priorityPair.p))
fillField(priorityPair.p, password);

return;
Expand All @@ -155,9 +163,9 @@ var filler = (function() {
for (var i = 0; i < userPasswordPairs.length; i++) {
var pair = userPasswordPairs[i];
if (!filled && isElementInViewport(pair.u) && isElementInViewport(pair.p)
&& pair.p.is(":visible")) {
&& isVisible(pair.p)) {
filled = fillField(pair.p, password);
if (pair.u.is(":visible")) {
if (isVisible(pair.u)) {
//sometimes the username is invisible, i.e. google login
fillField(pair.u, username);
}
Expand All @@ -168,17 +176,17 @@ var filler = (function() {
if (!filled) {
for (var i=0; i<lonelyPasswords.length; i++) {
var lonelyPassword = lonelyPasswords[i];
if (!filled && isElementInViewport(lonelyPassword) && lonelyPassword.is(':visible')) {
if (!filled && isElementInViewport(lonelyPassword) && isVisible(lonelyPassword)) {
filled = fillField(lonelyPassword, password);
}
}
}
}

function fillField(field, val) {
field.value = val;
var filled = (field.value === val);
sendKeyEvent(field);
field.val(val);
var filled = (field.val() === val);
return filled;
}

Expand All @@ -195,20 +203,15 @@ var filler = (function() {
for (var i in eventsToFire) {
var evt = document.createEvent(eventsToFire[i]);
evt.initEvent(i, true, true);
field.get(0).dispatchEvent(evt);
field.dispatchEvent(evt);
}
});
}

/**
function to determine if element is visible
*/
* function to determine if element is in the part of the screen on the monitor
*/
function isElementInViewport(el) {
//special bonus for those using jQuery
if (el instanceof $) {
el = el[0];
}

var rect = el.getBoundingClientRect();
return (
rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
Expand Down
11 changes: 6 additions & 5 deletions chrome.manifest.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "KeePass Tusk - A better password manager",
"name": "KeePass Tusk - Password Access and Autofill",
"short_name": "KeePass Tusk",
"version": "2018.2.17",
"manifest_version": 2,
"minimum_chrome_version": "48",
"description": "Readonly KeePass password database integration for Chrome™",
"icons": {
"16": "dist/logo_16.png",
"48": "dist/logo_48.png"
"16": "assets/icons/logo_16.png",
"48": "assets/icons/logo_48.png"
},
"oauth2": {
"client_id": "876467817034-al13p9m2bphgregs0rij76n1tumakcqr.apps.googleusercontent.com",
Expand All @@ -18,12 +18,13 @@
"key":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhoF/A6nYIxSHW2AekTQRJga9QodwEJBTeAA5r0tW9djrTHY3Ei0FdnUE1FrH2Hx03tsj4RjXMWDHtsqMg4REJdFNzndsRKWvliGomXtxE8XByawJf/NGx0/imAtVBrHc846D/Bn4q1dRaRauqkPMKgpcHoPeg+uLTBIfAn5qPgLlvLLqNSKRg6zGYkm0iBYFiyLd1cqWjsDrVhant90W5rE7qmGQPXZudkc2ejtijuMJL4CF9BeQXOVv/9a0XzAwNbArSr+zHnNOicZPyeEnT7mujFDvLRzXvi7OPW+8mdEsm3AeagKZ6bGUuqyzwxs8XlysWqJsXBoX6tjZCGGVpQIDAQAB",
"background": {
"scripts": [
"dist/background.build.js"
"dll/dll.library.js",
"build/background.build.js"
]
},
"incognito": "split",
"browser_action": {
"default_icon": "dist/logo_38.png",
"default_icon": "assets/icons/logo_38.png",
"default_popup": "popup.html",
"default_title": "KeePass Tusk"
},
Expand Down
105 changes: 105 additions & 0 deletions dll/dll.library.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dll/library-manifest.json

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions firefox.manifest.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
{
"name": "KeePass Tusk - A better password manager",
"name": "KeePass Tusk - Password Access and Autofill",
"short_name": "KeePass Tusk",
"version": "2018.2.17",
"manifest_version": 2,
"minimum_chrome_version": "48",
"description": "Readonly KeePass password database integration for Firefox",
"icons": {
"16": "dist/logo_16.png",
"48": "dist/logo_48.png"
"16": "assets/icons/logo_16.png",
"48": "assets/icons/logo_48.png"
},
"background": {
"scripts": [
"dist/background.build.js"
"dll/dll.library.js",
"build/background.build.js"
]
},
"browser_action": {
"default_icon": "dist/logo_38.png",
"default_icon": "assets/icons/logo_38.png",
"default_popup": "popup.html",
"default_title": "KeePass Tusk"
},
Expand Down
2 changes: 1 addition & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ gulp.task('webpack', function() {
console.log(err);
this.emit('end');
}))
.pipe(gulp.dest('dist'));
.pipe(gulp.dest('build'));
});

gulp.task('webpacktests', function () {
Expand Down
20 changes: 16 additions & 4 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const getValidTokens = tokenString => {
return tokenString.toLowerCase().split(/\.|\s|\//).filter(t => {
return (t && t !== "com" && t !== "www" && t.length > 1)
})
} // end getValidTokens
}

const parseUrl = url => {
if (url && !url.indexOf('http') == 0)
Expand All @@ -19,9 +19,9 @@ const parseUrl = url => {
var parser = document.createElement('a')
parser.href = url
return parser
} // end parseUrl
}

function guid() {
const guid = () => {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
Expand All @@ -30,9 +30,21 @@ function guid() {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

/**
* function to tell if the element can be seen by a human.
* @param el DOM element
* @returns booleans
*/
const isVisible = el => {
return el.offsetWidth > 0 &&
el.offsetHeight > 0 &&
parseFloat(window.getComputedStyle(el).getPropertyValue('opacity')) > .1
}

export {
getValidTokens,
parseUrl,
urlencode,
guid
guid,
isVisible
}
5 changes: 3 additions & 2 deletions options.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
<head>
<meta charset="utf-8">
<!-- Static compiled filesheets -->
<link rel="stylesheet" href="dist/css/options.css">
<link rel="stylesheet" href="build/css/options.css">
<script src="dll/dll.library.js"></script>
<title>Tusk</title>
</head>
<body>
<div id="app">
<script src="dist/options.build.js"></script>
<script src="build/options.build.js"></script>
</div>
</body>
</html>
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
"private": true,
"scripts": {
"prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules",
"build": "cross-env NODE_ENV=production webpack --progress --config webpack.config.js",
"build-tests": "cross-env NODE_ENV=test webpack --config webpack.test.config.js --progress",
"build-dll": "cross-env NODE_ENV=dll webpack --config webpack.dll.js --progress",
"bundle": "./packer.sh chrome && ./packer.sh firefox",
"clean": "rm -rf dist/ *.zip manifest.json demo*",
"clean": "rm -rf build/ *.zip manifest.json demo*",
"watch": "gulp watch",
"watch-tests": "gulp watchtests"
},
Expand All @@ -20,7 +21,6 @@
"base64-arraybuffer": "^0.1.5",
"case": "^1.5.4",
"font-awesome": "^4.7.0",
"jquery": "^3.2.1",
"json-formatter-js": "^2.2.0",
"kdbxweb": "^1.1.0",
"keeweb": "https://github.com/keeweb/keeweb",
Expand Down
2 changes: 1 addition & 1 deletion packer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ TARGET_BROWSER=$1
[ -z $TARGET_BROWSER ] && echo "Usage: ./packer.sh [chrome|firefox]" && exit 1

cp $TARGET_BROWSER.manifest.json manifest.json
zip -r $TARGET_BROWSER.tusk.zip dist/ popup.html options.html manifest.json
zip -r $TARGET_BROWSER.tusk.zip build/ assets/ dll/ popup.html options.html manifest.json
rm -rf ./demo-$TARGET_BROWSER
mkdir -p demo-$TARGET_BROWSER
cp $TARGET_BROWSER.tusk.zip ./demo-$TARGET_BROWSER
Expand Down
7 changes: 4 additions & 3 deletions popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
<head>
<meta charset="utf-8">
<title>Tusk</title>
<link rel="stylesheet" href="dist/css/popup.css">
<script src="dist/argon2.wasm"></script>
<link rel="stylesheet" href="build/css/popup.css">
<script src="dll/dll.library.js"></script>
<script src="assets/argon2.wasm"></script>
</head>
<body>
<div id="app">
<script src="dist/popup.build.js"></script>
<script src="build/popup.build.js"></script>
</div>
</body>
</html>
2 changes: 1 addition & 1 deletion services/dropboxFileManager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
const Base64 = require('base64-arraybuffer')
import axios from 'axios/dist/axios.min.js'
const axios = require('axios')
import {
ChromePromiseApi
} from '$lib/chrome-api-promise.js'
Expand Down
3 changes: 1 addition & 2 deletions services/googleDrivePasswordFileManager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const Base64 = require('base64-arraybuffer')

import axios from 'axios/dist/axios.min.js'
const axios = require('axios')
import {
ChromePromiseApi
} from '$lib/chrome-api-promise.js'
Expand Down
Loading

0 comments on commit 4d856b1

Please sign in to comment.