-
Notifications
You must be signed in to change notification settings - Fork 437
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ebca7b6
commit 058b706
Showing
10 changed files
with
186 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
export function coerceToBase64Url(thing, name) { | ||
// Array or ArrayBuffer to Uint8Array | ||
if (Array.isArray(thing)) { | ||
thing = Uint8Array.from(thing); | ||
} | ||
|
||
if (thing instanceof ArrayBuffer) { | ||
thing = new Uint8Array(thing); | ||
} | ||
|
||
// Uint8Array to base64 | ||
if (thing instanceof Uint8Array) { | ||
var str = ""; | ||
var len = thing.byteLength; | ||
|
||
for (var i = 0; i < len; i++) { | ||
str += String.fromCharCode(thing[i]); | ||
} | ||
thing = window.btoa(str); | ||
} | ||
|
||
if (typeof thing !== "string") { | ||
throw new Error("could not coerce '" + name + "' to string"); | ||
} | ||
|
||
// base64 to base64url | ||
// NOTE: "=" at the end of challenge is optional, strip it off here | ||
thing = thing.replace(/\+/g, "-").replace(/\//g, "_").replace(/=*$/g, ""); | ||
|
||
return thing; | ||
} | ||
|
||
export function coerceToArrayBuffer(thing, name) { | ||
if (typeof thing === "string") { | ||
// base64url to base64 | ||
thing = thing.replace(/-/g, "+").replace(/_/g, "/"); | ||
|
||
// base64 to Uint8Array | ||
var str = window.atob(thing); | ||
var bytes = new Uint8Array(str.length); | ||
for (var i = 0; i < str.length; i++) { | ||
bytes[i] = str.charCodeAt(i); | ||
} | ||
thing = bytes; | ||
} | ||
|
||
// Array to Uint8Array | ||
if (Array.isArray(thing)) { | ||
thing = new Uint8Array(thing); | ||
} | ||
|
||
// Uint8Array to ArrayBuffer | ||
if (thing instanceof Uint8Array) { | ||
thing = thing.buffer; | ||
} | ||
|
||
// error if none of the above worked | ||
if (!(thing instanceof ArrayBuffer)) { | ||
throw new TypeError("could not coerce '" + name + "' to ArrayBuffer"); | ||
} | ||
|
||
return thing; | ||
} |
39 changes: 18 additions & 21 deletions
39
internal/api/ui/login/static/resources/scripts/webauthn.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,28 @@ | ||
function checkWebauthnSupported(button, func) { | ||
let support = document.getElementsByClassName("wa-support"); | ||
let noSupport = document.getElementsByClassName("wa-no-support"); | ||
if (!window.PublicKeyCredential) { | ||
for (let item of noSupport) { | ||
item.classList.remove('hidden'); | ||
} | ||
for (let item of support) { | ||
item.classList.add('hidden'); | ||
} | ||
return; | ||
let support = document.getElementsByClassName("wa-support"); | ||
let noSupport = document.getElementsByClassName("wa-no-support"); | ||
if (!window.PublicKeyCredential) { | ||
for (let item of noSupport) { | ||
item.classList.remove("hidden"); | ||
} | ||
document.getElementById(button).addEventListener('click', func); | ||
for (let item of support) { | ||
item.classList.add("hidden"); | ||
} | ||
return; | ||
} | ||
document.getElementById(button).addEventListener("click", func); | ||
} | ||
|
||
function webauthnError(error) { | ||
let err = document.getElementById('wa-error'); | ||
err.getElementsByClassName('cause')[0].innerText = error.message; | ||
err.classList.remove('hidden'); | ||
let err = document.getElementById("wa-error"); | ||
err.getElementsByClassName("cause")[0].innerText = error.message; | ||
err.classList.remove("hidden"); | ||
} | ||
|
||
function bufferDecode(value) { | ||
return decode(value); | ||
function bufferDecode(value, name) { | ||
return coerceToArrayBuffer(value, name); | ||
} | ||
|
||
function bufferEncode(value) { | ||
return encode(value) | ||
.replace(/\+/g, "-") | ||
.replace(/\//g, "_") | ||
.replace(/=/g, ""); | ||
function bufferEncode(value, name) { | ||
return coerceToBase64Url(value, name); | ||
} |
77 changes: 45 additions & 32 deletions
77
internal/api/ui/login/static/resources/scripts/webauthn_login.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,54 @@ | ||
document.addEventListener('DOMContentLoaded', checkWebauthnSupported('btn-login', login)); | ||
document.addEventListener( | ||
"DOMContentLoaded", | ||
checkWebauthnSupported("btn-login", login) | ||
); | ||
|
||
function login() { | ||
document.getElementById('wa-error').classList.add('hidden'); | ||
document.getElementById("wa-error").classList.add("hidden"); | ||
|
||
let makeAssertionOptions = JSON.parse(atob(document.getElementsByName('credentialAssertionData')[0].value)); | ||
makeAssertionOptions.publicKey.challenge = bufferDecode(makeAssertionOptions.publicKey.challenge); | ||
makeAssertionOptions.publicKey.allowCredentials.forEach(function (listItem) { | ||
listItem.id = bufferDecode(listItem.id) | ||
}); | ||
navigator.credentials.get({ | ||
publicKey: makeAssertionOptions.publicKey | ||
}).then(function (credential) { | ||
verifyAssertion(credential); | ||
}).catch(function (err) { | ||
webauthnError(err); | ||
let makeAssertionOptions = JSON.parse( | ||
atob(document.getElementsByName("credentialAssertionData")[0].value) | ||
); | ||
makeAssertionOptions.publicKey.challenge = bufferDecode( | ||
makeAssertionOptions.publicKey.challenge, | ||
"publicKey.challenge" | ||
); | ||
makeAssertionOptions.publicKey.allowCredentials.forEach(function (listItem) { | ||
listItem.id = bufferDecode(listItem.id, "publicKey.allowCredentials.id"); | ||
}); | ||
navigator.credentials | ||
.get({ | ||
publicKey: makeAssertionOptions.publicKey, | ||
}) | ||
.then(function (credential) { | ||
verifyAssertion(credential); | ||
}) | ||
.catch(function (err) { | ||
webauthnError(err); | ||
}); | ||
} | ||
|
||
function verifyAssertion(assertedCredential) { | ||
let authData = new Uint8Array(assertedCredential.response.authenticatorData); | ||
let clientDataJSON = new Uint8Array(assertedCredential.response.clientDataJSON); | ||
let rawId = new Uint8Array(assertedCredential.rawId); | ||
let sig = new Uint8Array(assertedCredential.response.signature); | ||
let userHandle = new Uint8Array(assertedCredential.response.userHandle); | ||
let authData = new Uint8Array(assertedCredential.response.authenticatorData); | ||
let clientDataJSON = new Uint8Array( | ||
assertedCredential.response.clientDataJSON | ||
); | ||
let rawId = new Uint8Array(assertedCredential.rawId); | ||
let sig = new Uint8Array(assertedCredential.response.signature); | ||
let userHandle = new Uint8Array(assertedCredential.response.userHandle); | ||
|
||
let data = JSON.stringify({ | ||
id: assertedCredential.id, | ||
rawId: bufferEncode(rawId), | ||
type: assertedCredential.type, | ||
response: { | ||
authenticatorData: bufferEncode(authData), | ||
clientDataJSON: bufferEncode(clientDataJSON), | ||
signature: bufferEncode(sig), | ||
userHandle: bufferEncode(userHandle), | ||
}, | ||
}) | ||
let data = JSON.stringify({ | ||
id: assertedCredential.id, | ||
rawId: bufferEncode(rawId), | ||
type: assertedCredential.type, | ||
response: { | ||
authenticatorData: bufferEncode(authData), | ||
clientDataJSON: bufferEncode(clientDataJSON), | ||
signature: bufferEncode(sig), | ||
userHandle: bufferEncode(userHandle), | ||
}, | ||
}); | ||
|
||
document.getElementsByName('credentialData')[0].value = btoa(data); | ||
document.getElementsByTagName('form')[0].submit(); | ||
} | ||
document.getElementsByName("credentialData")[0].value = btoa(data); | ||
document.getElementsByTagName("form")[0].submit(); | ||
} |
83 changes: 51 additions & 32 deletions
83
internal/api/ui/login/static/resources/scripts/webauthn_register.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,61 @@ | ||
document.addEventListener('DOMContentLoaded', checkWebauthnSupported('btn-register', registerCredential)); | ||
document.addEventListener( | ||
"DOMContentLoaded", | ||
checkWebauthnSupported("btn-register", registerCredential) | ||
); | ||
|
||
function registerCredential() { | ||
document.getElementById('wa-error').classList.add('hidden'); | ||
document.getElementById("wa-error").classList.add("hidden"); | ||
|
||
let opt = JSON.parse(atob(document.getElementsByName('credentialCreationData')[0].value)); | ||
opt.publicKey.challenge = bufferDecode(opt.publicKey.challenge); | ||
opt.publicKey.user.id = bufferDecode(opt.publicKey.user.id); | ||
if (opt.publicKey.excludeCredentials) { | ||
for (let i = 0; i < opt.publicKey.excludeCredentials.length; i++) { | ||
if (opt.publicKey.excludeCredentials[i].id !== null) { | ||
opt.publicKey.excludeCredentials[i].id = bufferDecode(opt.publicKey.excludeCredentials[i].id); | ||
} | ||
} | ||
let opt = JSON.parse( | ||
atob(document.getElementsByName("credentialCreationData")[0].value) | ||
); | ||
opt.publicKey.challenge = bufferDecode( | ||
opt.publicKey.challenge, | ||
"publicKey.challenge" | ||
); | ||
opt.publicKey.user.id = bufferDecode( | ||
opt.publicKey.user.id, | ||
"publicKey.user.id" | ||
); | ||
if (opt.publicKey.excludeCredentials) { | ||
for (let i = 0; i < opt.publicKey.excludeCredentials.length; i++) { | ||
if (opt.publicKey.excludeCredentials[i].id !== null) { | ||
opt.publicKey.excludeCredentials[i].id = bufferDecode( | ||
opt.publicKey.excludeCredentials[i].id, | ||
"publicKey.excludeCredentials" | ||
); | ||
} | ||
} | ||
navigator.credentials.create({ | ||
publicKey: opt.publicKey | ||
}).then(function (credential) { | ||
createCredential(credential); | ||
}).catch(function (err) { | ||
webauthnError(err); | ||
} | ||
navigator.credentials | ||
.create({ | ||
publicKey: opt.publicKey, | ||
}) | ||
.then(function (credential) { | ||
createCredential(credential); | ||
}) | ||
.catch(function (err) { | ||
webauthnError(err); | ||
}); | ||
} | ||
|
||
function createCredential(newCredential) { | ||
let attestationObject = new Uint8Array(newCredential.response.attestationObject); | ||
let clientDataJSON = new Uint8Array(newCredential.response.clientDataJSON); | ||
let rawId = new Uint8Array(newCredential.rawId); | ||
let attestationObject = new Uint8Array( | ||
newCredential.response.attestationObject | ||
); | ||
let clientDataJSON = new Uint8Array(newCredential.response.clientDataJSON); | ||
let rawId = new Uint8Array(newCredential.rawId); | ||
|
||
let data = JSON.stringify({ | ||
id: newCredential.id, | ||
rawId: bufferEncode(rawId), | ||
type: newCredential.type, | ||
response: { | ||
attestationObject: bufferEncode(attestationObject), | ||
clientDataJSON: bufferEncode(clientDataJSON), | ||
}, | ||
}); | ||
let data = JSON.stringify({ | ||
id: newCredential.id, | ||
rawId: bufferEncode(rawId), | ||
type: newCredential.type, | ||
response: { | ||
attestationObject: bufferEncode(attestationObject), | ||
clientDataJSON: bufferEncode(clientDataJSON), | ||
}, | ||
}); | ||
|
||
document.getElementsByName('credentialData')[0].value = btoa(data); | ||
document.getElementsByTagName('form')[0].submit(); | ||
} | ||
document.getElementsByName("credentialData")[0].value = btoa(data); | ||
document.getElementsByTagName("form")[0].submit(); | ||
} |
8 changes: 4 additions & 4 deletions
8
internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
2 changes: 1 addition & 1 deletion
2
internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css.map
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters