Skip to content

Commit

Permalink
add autofill command
Browse files Browse the repository at this point in the history
  • Loading branch information
Sneezry committed Jan 7, 2022
1 parent 05dbda0 commit 528bef3
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 136 deletions.
3 changes: 3 additions & 0 deletions manifests/manifest-chrome.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
"_execute_browser_action": {},
"scan-qr": {
"description": "Scan a QR code"
},
"autofill": {
"description": "Autofill the matched code"
}
},
"options_ui": {
Expand Down
3 changes: 3 additions & 0 deletions manifests/manifest-edge.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
"_execute_browser_action": {},
"scan-qr": {
"description": "Scan a QR code"
},
"autofill": {
"description": "Autofill the matched code"
}
},
"options_ui": {
Expand Down
3 changes: 3 additions & 0 deletions manifests/manifest-firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
"_execute_browser_action": {},
"scan-qr": {
"description": "Scan a QR code"
},
"autofill": {
"description": "Autofill the matched code"
}
},
"options_ui": {
Expand Down
55 changes: 55 additions & 0 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Encryption } from "./models/encryption";
import { EntryStorage, ManagedStorage } from "./models/storage";
import { Dropbox, Drive, OneDrive } from "./models/backup";
import * as uuid from "uuid/v4";
import { getSiteName, getMatchedEntries } from "./utils";
import { CodeState } from "./models/otp";

import { getOTPAuthPerLineFromOPTAuthMigration } from "./models/migration";

Expand Down Expand Up @@ -560,6 +562,59 @@ chrome.commands.onCommand.addListener(async (command: string) => {
});
break;

case "autofill":
await new Promise(
(resolve: () => void, reject: (reason: Error) => void) => {
try {
return chrome.tabs.executeScript(
{ file: "/dist/content.js" },
() => {
chrome.tabs.insertCSS({ file: "/css/content.css" }, resolve);
}
);
} catch (error) {
console.error(error);
return reject(error);
}
}
);

if (cachedPassphrase === "") {
return;
}

chrome.tabs.query(
{ active: true, lastFocusedWindow: true },
async (tabs) => {
const tab = tabs[0];
if (!tab || !tab.id) {
return;
}
contentTab = tab;

const siteName = await getSiteName();
const entries = await EntryStorage.get();
const matchedEntries = getMatchedEntries(siteName, entries);

if (matchedEntries && matchedEntries.length === 1) {
const entry = matchedEntries[0];
const encryption = new Encryption(cachedPassphrase);
entry.applyEncryption(encryption);

if (
entry.code !== CodeState.Encrypted &&
entry.code !== CodeState.Invalid
) {
chrome.tabs.sendMessage(tab.id, {
action: "pastecode",
code: matchedEntries[0].code,
});
}
}
}
);
break;

default:
break;
}
Expand Down
139 changes: 3 additions & 136 deletions src/store/Accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Encryption } from "../models/encryption";
import * as CryptoJS from "crypto-js";
import { OTPType, OTPAlgorithm } from "../models/otp";
import { ActionContext } from "vuex";
import { getSiteName, getMatchedEntriesHash } from "../utils";

export class Accounts implements Module {
async getModule() {
Expand All @@ -22,7 +23,7 @@ export class Accounts implements Module {
sectorOffset: 0, // Offset in seconds for animations
second: 0, // Offset in seconds for math
filter: true,
siteName: await this.getSiteName(),
siteName: await getSiteName(),
showSearch: false,
exportData: await EntryStorage.getExport(entries),
exportEncData: await EntryStorage.getExport(entries, true),
Expand All @@ -41,7 +42,7 @@ export class Accounts implements Module {
);
},
matchedEntries: (state: AccountsState) => {
return this.matchedEntries(state.siteName, state.entries);
return getMatchedEntriesHash(state.siteName, state.entries);
},
currentlyEncrypted(state: AccountsState) {
for (const entry of state.entries) {
Expand Down Expand Up @@ -513,82 +514,6 @@ export class Accounts implements Module {
};
}

private async getSiteName() {
return new Promise((resolve: (value: Array<string | null>) => void) => {
chrome.tabs.query({ active: true, lastFocusedWindow: true }, (tabs) => {
const tab = tabs[0];
const query = new URLSearchParams(
document.location.search.substring(1)
);

let title: string | null;
let url: string | null;
const titleFromQuery = query.get("title");
const urlFromQuery = query.get("url");

if (titleFromQuery && urlFromQuery) {
title = decodeURIComponent(titleFromQuery);
url = decodeURIComponent(urlFromQuery);
} else {
if (!tab) {
return resolve([null, null]);
}

title = tab.title?.replace(/[^a-z0-9]/gi, "").toLowerCase() ?? null;
url = tab.url ?? null;
}

if (!url) {
return resolve([title, null]);
}

const urlParser = new URL(url);
const hostname = urlParser.hostname; // it's always lower case

// try to parse name from hostname
// i.e. hostname is www.example.com
// name should be example
let nameFromDomain = "";

// ip address
if (/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
nameFromDomain = hostname;
}

// local network
if (hostname.indexOf(".") === -1) {
nameFromDomain = hostname;
}

const hostLevelUnits = hostname.split(".");

if (hostLevelUnits.length === 2) {
nameFromDomain = hostLevelUnits[0];
}

// www.example.com
// example.com.cn
if (hostLevelUnits.length > 2) {
// example.com.cn
if (
["com", "net", "org", "edu", "gov", "co"].indexOf(
hostLevelUnits[hostLevelUnits.length - 2]
) !== -1
) {
nameFromDomain = hostLevelUnits[hostLevelUnits.length - 3];
} else {
// www.example.com
nameFromDomain = hostLevelUnits[hostLevelUnits.length - 2];
}
}

nameFromDomain = nameFromDomain.replace(/-/g, "").toLowerCase();

return resolve([title, nameFromDomain, hostname]);
});
});
}

private getCachedPassphrase() {
return new Promise((resolve: (value: string) => void) => {
chrome.runtime.sendMessage(
Expand All @@ -604,62 +529,4 @@ export class Accounts implements Module {
const otpEntries = await EntryStorage.get();
return otpEntries;
}

private matchedEntries(
siteName: Array<string | null>,
entries: OTPEntryInterface[]
) {
if (siteName.length < 2) {
return false;
}

const matched = [];

for (const entry of entries) {
if (this.isMatchedEntry(siteName, entry)) {
matched.push(entry.hash);
}
}

return matched;
}

private isMatchedEntry(
siteName: Array<string | null>,
entry: OTPEntryInterface
) {
if (!entry.issuer) {
return false;
}

const issuerHostMatches = entry.issuer.split("::");
const issuer = issuerHostMatches[0]
.replace(/[^0-9a-z]/gi, "")
.toLowerCase();

if (!issuer) {
return false;
}

const siteTitle = siteName[0] || "";
const siteNameFromHost = siteName[1] || "";
const siteHost = siteName[2] || "";

if (issuerHostMatches.length > 1) {
if (siteHost && siteHost.indexOf(issuerHostMatches[1]) !== -1) {
return true;
}
}
// site title should be more detailed
// so we use siteTitle.indexOf(issuer)
if (siteTitle && siteTitle.indexOf(issuer) !== -1) {
return true;
}

if (siteNameFromHost && issuer.indexOf(siteNameFromHost) !== -1) {
return true;
}

return false;
}
}
Loading

0 comments on commit 528bef3

Please sign in to comment.