Added Multiple choice when allowCredentials is empty

This commit is contained in:
2025-05-14 03:17:08 +09:00
parent 70fba2b72e
commit 8bdac9e648
2 changed files with 69 additions and 13 deletions

25
fido.py
View File

@@ -313,6 +313,7 @@ class VirtualFidoDevice:
allowed_credential = data.get("allowCredentials") allowed_credential = data.get("allowCredentials")
cred = None cred = None
if allowed_credential: if allowed_credential:
for credential in allowed_credential: for credential in allowed_credential:
credential_id_b64 = credential["id"] credential_id_b64 = credential["id"]
@@ -320,10 +321,22 @@ class VirtualFidoDevice:
cred = self.credentials[credential_id_b64] cred = self.credentials[credential_id_b64]
break break
else: else:
for credential_id_b64, my_credential in self.credentials.items(): match_creds = []
if my_credential["rp_id"] == rp_id.decode(): for cid, cr in self.credentials.items():
cred = my_credential if cr["rp_id"] == rp_id.decode():
break match_creds.append(cid)
if len(match_creds) == 1:
cred = self.credentials[cid]
else:
results = []
for cr in match_creds:
current = data.copy()
current["allowCredentials"] = [{"id": cr}]
results.append(self.get(current, origin))
return results
if not cred: if not cred:
raise self.CredNotFoundError() raise self.CredNotFoundError()
@@ -360,7 +373,9 @@ class VirtualFidoDevice:
"signature": self._b64url(signature), "signature": self._b64url(signature),
"userHandle": cred["user_id"] "userHandle": cred["user_id"]
}, },
"type": "public-key" "type": "public-key",
"username": cred["user_name"],
"created": cred["created"]
} }
return response return response

View File

@@ -56,6 +56,43 @@ function myFetch(url, options = {}) {
}); });
} }
function showCredentialSelectionPopup(credentials) {
return new Promise((resolve) => {
const popup = document.createElement("div");
popup.style.position = "fixed";
popup.style.top = "20px";
popup.style.right = "20px";
popup.style.backgroundColor = "#fff";
popup.style.color = "#000";
popup.style.border = "1px solid #bbb";
popup.style.borderRadius = "5px";
popup.style.padding = "15px";
popup.style.zIndex = "9999";
popup.style.maxWidth = "300px";
const title = document.createElement("h3");
title.textContent = "Select credential";
title.style.margin = "0 0 10px 0";
popup.appendChild(title);
credentials.forEach((cred, index) => {
const option = document.createElement("div");
option.style.padding = "8px 10px";
option.style.cursor = "pointer";
const createdDate = new Date(cred.created * 1000).toLocaleString();
option.innerHTML = `
<strong>${cred.username || 'Unknown user'}</strong>
<div style="font-size: 0.8em; color: #666;">Created: ${createdDate}</div>
`;
option.addEventListener("mouseover", () => { option.style.backgroundColor = "#f0f0f0"; });
option.addEventListener("mouseout", () => { option.style.backgroundColor = "transparent"; });
option.addEventListener("click", () => { document.body.removeChild(popup); resolve(cred); });
popup.appendChild(option);
});
document.body.appendChild(popup);
});
}
const origGet = navigator.credentials.get; const origGet = navigator.credentials.get;
const origCreate = navigator.credentials.create; const origCreate = navigator.credentials.create;
@@ -79,19 +116,23 @@ navigator.credentials.get = async function(options) {
if (!response.ok) throw new Error(`server error: ${response.status}`) if (!response.ok) throw new Error(`server error: ${response.status}`)
const resp = await response.json() const resp = await response.json()
console.log("server response:", resp) console.log("server response:", resp)
let cred = resp;
if (Array.isArray(resp) && resp.length > 0) {
cred = await showCredentialSelectionPopup(resp);
}
const credential = { const credential = {
id: resp.id, id: cred.id,
type: resp.type, type: cred.type,
rawId: b64ab(resp.rawId), rawId: b64ab(cred.rawId),
response: { response: {
authenticatorData: b64ab(resp.response.authenticatorData), authenticatorData: b64ab(cred.response.authenticatorData),
clientDataJSON: b64ab(resp.response.clientDataJSON), clientDataJSON: b64ab(cred.response.clientDataJSON),
signature: b64ab(resp.response.signature) signature: b64ab(cred.response.signature)
}, },
getClientExtensionResults: () => { return {} } getClientExtensionResults: () => { return {} }
} }
if (resp.response.userHandle) { if (cred.response.userHandle) {
credential.response.userHandle = b64ab(resp.response.userHandle); credential.response.userHandle = b64ab(cred.response.userHandle);
} }
console.log(credential) console.log(credential)
return credential; return credential;