diff --git a/dist/chromium/popup.html b/dist/chromium/popup.html index adadc38..f371d9b 100644 --- a/dist/chromium/popup.html +++ b/dist/chromium/popup.html @@ -19,15 +19,8 @@
PSK Options -
- Backup File Sync: -
-
- Delegation File Sync: -
-
- -
+ +
diff --git a/package-lock.json b/package-lock.json index de08684..0ae85f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1341,6 +1341,14 @@ "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", "dev": true }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -3805,6 +3813,24 @@ "readable-stream": "^2.3.6" } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -6862,8 +6888,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nan": { "version": "2.14.0", diff --git a/package.json b/package.json index 2ed46ac..d3e6f38 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@types/loglevel": "^1.6.3", "@types/webappsec-credential-management": "^0.3.11", "asn1js": "^2.0.26", + "axios": "^0.19.2", "bn.js": "^5.1.2", "cbor": "^4.3.0", "elliptic": "^6.5.3", diff --git a/src/background.ts b/src/background.ts index b23f4b7..a961642 100644 --- a/src/background.ts +++ b/src/background.ts @@ -2,7 +2,8 @@ import {disabledIcons, enabledIcons} from './constants'; import {getLogger} from './logging'; import {getOriginFromUrl, webauthnParse, webauthnStringify} from './utils'; import {processCredentialRequest, processCredentialCreation} from './webauthn'; -import {RecoveryKey, syncBackupKeys, syncDelegation} from "./recovery"; +import {BackupDeviceBaseUrl, RecoveryKey, pskSetup, pskRecovery} from "./recovery"; +import * as axios from 'axios'; const log = getLogger('background'); @@ -34,22 +35,14 @@ const requestPin = async (tabId: number, origin: string, newPin: boolean = true) return pin; }; -const syncBackup = async (backupContent) => { - log.debug('Sync Backup called'); - - await syncBackupKeys(backupContent); -}; - -const syncDel = async (delegationContent) => { - log.debug('Sync Delegation called'); - - await syncDelegation(delegationContent); +const setup = async () => { + log.debug('Setup called'); + await pskSetup(); }; -const recovery = async (n) => { - log.debug('Create recovery keys called') - - await RecoveryKey.generate(n); +const recovery = async () => { + log.debug('Recovery called!') + await pskRecovery(); } const create = async (msg, sender: chrome.runtime.MessageSender) => { @@ -122,14 +115,11 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { delete (pinProtectedCallbacks[msg.tabId]); } break; - case 'syncBackup': - syncBackup(msg.backup).then(() => alert("Backup file processed")); - break; - case 'syncDelegation': - syncDel(msg.delegation).then(() => alert("Delegation file processed")); + case 'setup': + setup().then(() => alert("Backup keys synchronized successfully!")); break; case 'recovery': - recovery(msg.amount).then(() => alert("Creating recovery keys finished")) + recovery().then(() => alert("Recovery finished successfully!")) break; default: sendResponse(null); diff --git a/src/popup.ts b/src/popup.ts index 7071ff3..082a631 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -11,54 +11,16 @@ $(() => { return; } - $('#delegationFile').on('change', function(evt: Event) { - const files = (evt.target).files; // FileList object - - // use the 1st file from the list - const f = files[0]; - - const reader = new FileReader(); - - // Closure to capture the file information. - reader.onload = (function(theFile) { - return function(e) { - chrome.runtime.sendMessage({ - delegation: e.target.result, - type: 'syncDelegation', - }); - }; - })(f); - - // Read in the image file as a data URL. - reader.readAsText(f); - }); - $('#backupFile').on('change', function(evt: Event) { + $('#Setup').on('click', function(evt: Event) { evt.preventDefault(); - const files = (evt.target).files; // FileList object - - // use the 1st file from the list - const f = files[0]; - - const reader = new FileReader(); - - // Closure to capture the file information. - reader.onload = (function(theFile) { - return function(e) { - chrome.runtime.sendMessage({ - backup: e.target.result, - type: 'syncBackup', - }); - }; - })(f); - - // Read in the image file as a data URL. - reader.readAsText(f); + chrome.runtime.sendMessage({ + type: 'setup', + }); }); - $('#recovery').on('click', function(evt: Event) { + $('#Recovery').on('click', function(evt: Event) { evt.preventDefault(); chrome.runtime.sendMessage({ - amount: 5, // ToDo Read real input type: 'recovery', }); }); diff --git a/src/recovery.ts b/src/recovery.ts index a8a66b3..93321f5 100644 --- a/src/recovery.ts +++ b/src/recovery.ts @@ -3,46 +3,80 @@ import {getLogger} from './logging'; import {getCompatibleKeyFromCryptoKey, ICOSECompatibleKey} from './crypto'; import {base64ToByteArray, byteArrayToBase64, getDomainFromOrigin} from './utils'; import {fetchExportContainer, saveExportContainer, saveKey} from './storage'; +import * as axios from "axios"; const log = getLogger('recovery'); export const PSK: string = 'psk' +export const BackupDeviceBaseUrl = 'http://localhost:8005' // ToDo Load from a config file + export type ExportContainerType = string const BACKUP: ExportContainerType = 'backup' const RECOVERY: ExportContainerType = 'recovery' const DELEGATION: ExportContainerType = 'delegation' -export async function syncBackupKeys (content) { - const jwk = JSON.parse(content); - let i; - const container = new Array(); - for (i = 0; i < jwk.length; ++i) { - const parsedKey = await parseJWK(jwk[i], []); - const id = base64ToByteArray(jwk[i].kid, true); - const encId = byteArrayToBase64(id, true); - const bckpKey = new BackupKey(parsedKey, encId); - const expBckpKey = await bckpKey.export(); - container.push(expBckpKey); - } - log.debug('Loaded backup keys', container); - - await saveExportContainer(BACKUP, container); +export async function pskSetup () { + const authId = prompt("Please enter a name for your authenticator", "MyAuth"); + const keyAmount: number = +prompt("How many backup keys should be created?", "5"); + + await axios.default.post(BackupDeviceBaseUrl + '/setup', {auth_id: authId, key_amount: keyAmount}) + .then(async function (response) { + log.debug(response) + const jwk = response.data; + let i; + const container = new Array(); + for (i = 0; i < jwk.length; ++i) { + const parsedKey = await parseJWK(jwk[i], []); + const id = base64ToByteArray(jwk[i].kid, true); + const encId = byteArrayToBase64(id, true); + const bckpKey = new BackupKey(parsedKey, encId); + const expBckpKey = await bckpKey.export(); + container.push(expBckpKey); + } + log.debug('Loaded backup keys', container); + + await saveExportContainer(BACKUP, container); + }) + .catch(function (error) { + log.error(error); + }) } -export async function syncDelegation (content) { - const rawDelegations = JSON.parse(content); - let i; - const container = new Array(); - for (i = 0; i < rawDelegations.length; ++i) { - const sign = rawDelegations[i].sign; - const srcCredId = base64ToByteArray(rawDelegations[i].src_cred_id, true); - const encSrcCredId = byteArrayToBase64(srcCredId, true); - const del = new Delegation(sign, encSrcCredId, rawDelegations[i].pub_rk); - container.push(del.export()); - } - log.debug("Loaded delegation", container); - await saveExportContainer(DELEGATION, container); +export async function pskRecovery () { + const authId = prompt("Which authenticator you want to replace?", "MyAuth"); + + await axios.default.get(BackupDeviceBaseUrl + '/recovery?authId=' + authId) + .then(async function (response1) { + log.debug(response1); + const keyAmount = response1.data.key_amount; + + const rkPub = await RecoveryKey.generate(keyAmount); + + await axios.default.post(BackupDeviceBaseUrl + '/recovery', {recovery_keys: rkPub, auth_id: authId}) + .then(async function (response2) { + log.debug(response2); + const rawDelegations = response2.data; + + let i; + const container = new Array(); + for (i = 0; i < rawDelegations.length; ++i) { + const sign = rawDelegations[i].sign; + const srcCredId = base64ToByteArray(rawDelegations[i].src_cred_id, true); + const encSrcCredId = byteArrayToBase64(srcCredId, true); + const del = new Delegation(sign, encSrcCredId, rawDelegations[i].pub_rk); + container.push(del.export()); + } + log.debug("Loaded delegation", container); + await saveExportContainer(DELEGATION, container); + }) + .catch(function (error) { + log.error(error); + }) + }) + .catch(function (error) { + log.error(error); + }) } export class ExportContainer { @@ -115,7 +149,7 @@ export class RecoveryKey { return new RecoveryKey(key, backupKey); } - static async generate(n: number) { + static async generate(n: number): Promise> { const jwk = new Array(); const container = new Array(); let i; @@ -137,17 +171,7 @@ export class RecoveryKey { await saveExportContainer(RECOVERY, container); - // Download recovery public keys as file - let json = [JSON.stringify(jwk)]; - let blob1 = new Blob(json, { type: "text/plain;charset=utf-8" }); - let link = (window.URL ? URL : webkitURL).createObjectURL(blob1); - let a = document.createElement("a"); - a.download = "recoveryKeys.json"; - a.href = link; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - log.debug("Downloading recovery keys completed"); + return jwk; } } diff --git a/src/storage.ts b/src/storage.ts index 463a88e..27f15c8 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -99,6 +99,7 @@ export const fetchKey = async (key: string, pin: string): Promise => if (resp[key] == null) { return rej("Key not found"); } + log.info('PIN', pin); const payload = base64ToByteArray(resp[key]); const saltByteLength = payload[0]; const ivByteLength = payload[1];