Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 26 additions & 14 deletions extension/authenticator.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@ window.authnTools = window.authnTools || {};
const initAuthenticator = async () => {
const authenticator = new window.AuthnDevice();
// Override storage handler to use chrome.storage.local
authenticator.handleStorage = function (data) {
if (data) {
// Save mode - return a promise or handle async
return new Promise((resolve, reject) => {
chrome.storage.local.set({ 'system_credentials': data }, () => {
console.log('Credentials saved to local storage');
resolve(data);
});
});
authenticator.handleStorage = async function (data = null) {
if (data !== null) {
await chrome.storage.local.set({ 'system_credentials': data }
);
console.log('Credentials saved to local storage');
return data;
} else {
return this.storage;
const result = await chrome.storage.local.get('system_credentials');
return result.system_credentials || [];
}
};
const result = await chrome.storage.local.get(['system_credentials', 'option@debugLogging', 'extension_salt', 'extension_ca_key']);
Expand Down Expand Up @@ -61,7 +59,7 @@ const initAuthenticator = async () => {
authenticator.legacyMasterkeySalt = legacySalt.buffer;
console.log('[Auth] Legacy salt fallback initialized (16 zeros).');

if (result.system_credentials) authenticator.storage = result.system_credentials;
authenticator.storage = result.system_credentials || [];
authenticator.debugLogging = result['option@debugLogging'] === true;
return authenticator;
};
Expand Down Expand Up @@ -142,9 +140,23 @@ const handleMessage = async (request, sender, sendResponse) => {
// So we need to manually ensure we save "authenticator.storage" if it changed?
// UNLESS we explicit save here.

debugLog('[Auth] Manually ensuring storage save...');
await new Promise(r => chrome.storage.local.set({ 'system_credentials': deviceInstance.storage }, r));
debugLog('[Auth] Manual save complete.');
//debugLog('[Auth] Manually ensuring storage save...');
//await new Promise(r => chrome.storage.local.set({ 'system_credentials': deviceInstance.storage }, r));
//debugLog('[Auth] Manual save complete.');


if (deviceInstance.storage) {
debugLog('[Auth] Saving credential storage...');
await new Promise(r =>
chrome.storage.local.set(
{ 'system_credentials': deviceInstance.storage },
r
)
);
debugLog('[Auth] Storage save complete.');
}


} else if (request.type === 'get' || request.authn === 'get') {
debugLog('[Auth] Get Options (Raw):', request.options);

Expand Down
149 changes: 117 additions & 32 deletions extension/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,62 +11,147 @@ let contentScriptPort = null;
// Listen for messages from content scripts (injected page)
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {

//console.log("BACKGROUND MESSAGE:", message);
//
// Popup is ready - send pend8ing WebAuthn request
//
if (message.type === 'authenticator_ready') {
// The popup is open and ready. Send the pending request.

console.log("AUTHENTICATOR READY");

if (pendingRequest) {
chrome.runtime.sendMessage(pendingRequest);
// pendingRequest = null; // Keep it until completion? No, simple flow.
}

return;
}

// Message from the authenticator popup (completion)
if (message.status === 'completed' || message.status === 'error') {
// Forward to the tab that requested it
//
// Response from authenticator popup
//
if (message.status === "completed" || message.status === "error") {

// console.log(
// "FULL COMPLETION MESSAGE:",
// message
// );

let credential = null;

if (message.credential) {
try {
credential = JSON.parse(message.credential);
console.log("PARSED CREDENTIAL:", credential);
} catch (e) {
console.error("FAILED TO PARSE CREDENTIAL:", e);
}
}

//
// Debug credential payload
//
if (message.credential) {

try {
let credential = JSON.parse(message.credential);

// If we have a stored tab ID from the pending request, use it.
console.log(
"PARSED CREDENTIAL:",
credential
);

// rawId
if (credential.rawId?.data) {
let rawId = new Uint8Array(credential.rawId.data);
console.log("FORWARDED RAW ID:",rawId.byteLength,rawId);
}

// authenticatorData
if (
credential.response?.authenticatorData?.data
) {

let authData = new Uint8Array(credential.response.authenticatorData.data);
console.log("FORWARDED AUTHDATA:",authData.byteLength);
}

// signature
if (credential.response?.signature?.data) {
let signature =
new Uint8Array(credential.response.signature.data
);

console.log("FORWARDED SIGNATURE:",signature.byteLength);

console.log(
"SIGNATURE HEX:",
Array.from(signature)
.map(
b =>
b.toString(16)
.padStart(2,"0")
)
.join("")
);
}

// userHandle
if (
credential.response?.userHandle?.data
) {

let userHandle =
new Uint8Array(
credential.response.userHandle.data
);

console.log("FORWARDED USER HANDLE:",userHandle.byteLength);
}


}
catch(e) {console.error("FAILED TO PARSE CREDENTIAL:",e);
}
}

// Send response back to requesting tab
if (pendingRequest && pendingRequest.requestingTabId) {
console.log("WebAuthnLinux: Forwarding response to tab " + pendingRequest.requestingTabId);
chrome.tabs.sendMessage(pendingRequest.requestingTabId, {
...message,
extensionResponse: true
});
// Clear pending request after completion?
// Maybe wait a bit or clear it now. Let's clear it to be clean.
// pendingRequest = null;
...message,
extensionResponse: true
});
// Clear request after completion
//
pendingRequest = null;
} else {
// Fallback: Query active tab (less reliable if popup is focused or user switched tabs)
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs.length > 0) {
chrome.tabs.sendMessage(tabs[0].id, {
...message,
extensionResponse: true // Flag to identify it
});
}
});
console.warn("No requesting tab stored");
}
return;
}

// Message from the content script (requesting auth)
if (message.action === 'trigger_authenticator') {
pendingRequest = message.data;
//console.log("AUTH REQUEST RECEIVED",message);
pendingRequest = message.data;
// Store the ID of the tab that requested this, so we can reply to the correct one later
// message.data might not have it, but 'sender' does.
// message.data might not have it, but 'sender' does.
if (sender.tab) {
pendingRequest.requestingTabId = sender.tab.id;
}

// Open the popup
// Open authenticator popup
chrome.windows.create({
url: "authenticator.html",
type: "popup",
width: 400,
height: 600,
focused: true
}, (window) => {
popupWindowId = window.id;
});
url: "authenticator.html",
type: "popup",
width: 400,
height: 600,
focused: true
}, (window) => {
if(window)
popupWindowId = window.id;
}
);

sendResponse({ started: true });
return true; // async response
Expand Down
Loading