mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-10 21:02:21 +00:00
feat: run on a single port (#3163)
* start v2 * start * run * some cleanup * remove v2 pkg again * simplify * webauthn * remove unused config * fix login path in Dockerfile * fix asset_generator.go * health handler * fix grpc web * refactor * merge * build new main.go * run new main.go * update logging pkg * fix error msg * update logging * cleanup * cleanup * go mod tidy * change localDevMode * fix customEndpoints * update logging * comments * change local flag to external configs * fix location generated go code * fix Co-authored-by: fforootd <florian@caos.ch>
This commit is contained in:
62
internal/api/ui/login/static/resources/scripts/avatar.js
Normal file
62
internal/api/ui/login/static/resources/scripts/avatar.js
Normal file
@@ -0,0 +1,62 @@
|
||||
const avatars = document.getElementsByClassName('lgn-avatar');
|
||||
for (let i = 0; i < avatars.length; i++) {
|
||||
const displayName = avatars[i].getAttribute('loginname');
|
||||
if (displayName) {
|
||||
const username = displayName.split('@')[0];
|
||||
let separator = '_';
|
||||
if (username.includes('-')) {
|
||||
separator = '-';
|
||||
}
|
||||
if (username.includes('.')) {
|
||||
separator = '.';
|
||||
}
|
||||
const split = username.split(separator);
|
||||
const initials = split[0].charAt(0) + (split[1] ? split[1].charAt(0) : '');
|
||||
avatars[i].getElementsByClassName('initials')[0].innerHTML = initials;
|
||||
|
||||
avatars[i].style.background = this.getColor(displayName);
|
||||
// set default white text instead of contrast text mode
|
||||
avatars[i].style.color = '#ffffff';
|
||||
}
|
||||
}
|
||||
|
||||
function getColor(userName) {
|
||||
const colors = [
|
||||
'linear-gradient(40deg, #B44D51 30%, rgb(241,138,138))',
|
||||
'linear-gradient(40deg, #B75073 30%, rgb(234,96,143))',
|
||||
'linear-gradient(40deg, #84498E 30%, rgb(214,116,230))',
|
||||
'linear-gradient(40deg, #705998 30%, rgb(163,131,220))',
|
||||
'linear-gradient(40deg, #5C6598 30%, rgb(135,148,222))',
|
||||
'linear-gradient(40deg, #7F90D3 30%, rgb(181,196,247))',
|
||||
'linear-gradient(40deg, #3E93B9 30%, rgb(150,215,245))',
|
||||
'linear-gradient(40deg, #3494A0 30%, rgb(71,205,222))',
|
||||
'linear-gradient(40deg, #25716A 30%, rgb(58,185,173))',
|
||||
'linear-gradient(40deg, #427E41 30%, rgb(97,185,96))',
|
||||
'linear-gradient(40deg, #89A568 30%, rgb(176,212,133))',
|
||||
'linear-gradient(40deg, #90924D 30%, rgb(187,189,98))',
|
||||
'linear-gradient(40deg, #E2B032 30%, rgb(245,203,99))',
|
||||
'linear-gradient(40deg, #C97358 30%, rgb(245,148,118))',
|
||||
'linear-gradient(40deg, #6D5B54 30%, rgb(152,121,108))',
|
||||
'linear-gradient(40deg, #6B7980 30%, rgb(134,163,177))',
|
||||
];
|
||||
|
||||
let hash = 0;
|
||||
if (userName.length === 0) {
|
||||
return colors[hash];
|
||||
}
|
||||
|
||||
hash = this.hashCode(userName);
|
||||
return colors[hash % colors.length];
|
||||
}
|
||||
|
||||
function hashCode(str, seed = 0) {
|
||||
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
||||
for (let i = 0, ch; i < str.length; i++) {
|
||||
ch = str.charCodeAt(i);
|
||||
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||
}
|
||||
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
||||
}
|
||||
68
internal/api/ui/login/static/resources/scripts/base64.js
Normal file
68
internal/api/ui/login/static/resources/scripts/base64.js
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* modified version of:
|
||||
*
|
||||
* base64-arraybuffer
|
||||
* https://github.com/niklasvh/base64-arraybuffer
|
||||
*
|
||||
* Copyright (c) 2012 Niklas von Hertzen
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
// Use a lookup table to find the index.
|
||||
let lookup = new Uint8Array(256);
|
||||
for (var i = 0; i < chars.length; i++) {
|
||||
lookup[chars.charCodeAt(i)] = i;
|
||||
}
|
||||
|
||||
function encode(arraybuffer) {
|
||||
let bytes = new Uint8Array(arraybuffer),
|
||||
i, len = bytes.length, base64 = "";
|
||||
|
||||
for (i = 0; i < len; i += 3) {
|
||||
base64 += chars[bytes[i] >> 2];
|
||||
base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
|
||||
base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
|
||||
base64 += chars[bytes[i + 2] & 63];
|
||||
}
|
||||
|
||||
if ((len % 3) === 2) {
|
||||
base64 = base64.substring(0, base64.length - 1) + "=";
|
||||
} else if (len % 3 === 1) {
|
||||
base64 = base64.substring(0, base64.length - 2) + "==";
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
|
||||
function decode(base64) {
|
||||
let bufferLength = base64.length * 0.75,
|
||||
len = base64.length, i, p = 0,
|
||||
encoded1, encoded2, encoded3, encoded4;
|
||||
|
||||
if (base64[base64.length - 1] === "=") {
|
||||
bufferLength--;
|
||||
if (base64[base64.length - 2] === "=") {
|
||||
bufferLength--;
|
||||
}
|
||||
}
|
||||
|
||||
let arraybuffer = new ArrayBuffer(bufferLength),
|
||||
bytes = new Uint8Array(arraybuffer);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
encoded1 = lookup[base64.charCodeAt(i)];
|
||||
encoded2 = lookup[base64.charCodeAt(i + 1)];
|
||||
encoded3 = lookup[base64.charCodeAt(i + 2)];
|
||||
encoded4 = lookup[base64.charCodeAt(i + 3)];
|
||||
|
||||
bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
|
||||
bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
|
||||
bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
|
||||
}
|
||||
|
||||
return arraybuffer;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
function CheckChangePwPolicy() {
|
||||
let policyElement = document.getElementById("change-new-password");
|
||||
let pwNew = policyElement.value;
|
||||
let pwNewConfirmation = document.getElementById("change-password-confirmation").value;
|
||||
|
||||
if (ComplexityPolicyCheck(policyElement, pwNew, pwNewConfirmation) === false) {
|
||||
policyElement.setAttribute("color", "warn");
|
||||
return false;
|
||||
} else {
|
||||
policyElement.setAttribute("color", "primary");
|
||||
}
|
||||
|
||||
return pwNew == pwNewConfirmation;
|
||||
}
|
||||
|
||||
let button = document.getElementById("change-password-button");
|
||||
disableSubmit(CheckChangePwPolicy, button);
|
||||
@@ -0,0 +1,6 @@
|
||||
const copyToClipboard = str => {
|
||||
navigator.clipboard.writeText(str);
|
||||
};
|
||||
|
||||
let copyButton = document.getElementById("copy");
|
||||
copyButton.addEventListener("click", copyToClipboard(copyButton.getAttribute("data-copy")));
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
let button = document.getElementById("submit-button");
|
||||
disableSubmit(undefined, button);
|
||||
@@ -0,0 +1,10 @@
|
||||
let buttons1 = document.getElementsByName("linkbutton");
|
||||
|
||||
for (let i = 0; i < buttons1.length; i++) {
|
||||
disableSubmit(undefined, buttons1[i]);
|
||||
}
|
||||
|
||||
let buttons2 = document.getElementsByName("autoregisterbutton");
|
||||
for (let i = 0; i < buttons2.length; i++) {
|
||||
disableSubmit(undefined, buttons2[i]);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
function disableSubmit(checks, button) {
|
||||
let form = document.getElementsByTagName('form')[0];
|
||||
let inputs = form.getElementsByTagName('input');
|
||||
if (button) {
|
||||
button.disabled = true;
|
||||
}
|
||||
addRequiredEventListener(inputs, checks, form, button);
|
||||
disableDoubleSubmit(form, button);
|
||||
|
||||
toggleButton(checks, form, inputs, button);
|
||||
}
|
||||
|
||||
function addRequiredEventListener(inputs, checks, form, button) {
|
||||
let eventType = 'input';
|
||||
for (i = 0; i < inputs.length; i++) {
|
||||
if (inputs[i].required) {
|
||||
eventType = 'input';
|
||||
if (inputs[i].type === 'checkbox') {
|
||||
eventType = 'click';
|
||||
}
|
||||
inputs[i].addEventListener(eventType, function () {
|
||||
toggleButton(checks, form, inputs, button);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function disableDoubleSubmit(form, button) {
|
||||
form.addEventListener('submit', function () {
|
||||
document.body.classList.add('waiting');
|
||||
button.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
function toggleButton(checks, form, inputs, button) {
|
||||
if (checks !== undefined) {
|
||||
if (checks() === false) {
|
||||
button.disabled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
const targetValue = !allRequiredDone(form, inputs);
|
||||
button.disabled = targetValue;
|
||||
}
|
||||
|
||||
function allRequiredDone(form, inputs) {
|
||||
for (i = 0; i < inputs.length; i++) {
|
||||
if (inputs[i].required) {
|
||||
if (inputs[i].type === 'checkbox' && !inputs[i].checked) {
|
||||
return false;
|
||||
}
|
||||
if (inputs[i].value === '') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
function CheckInitPwPolicy() {
|
||||
let policyElement = document.getElementById("password");
|
||||
let pwNew = policyElement.value;
|
||||
let pwNewConfirmation = document.getElementById("passwordconfirm").value;
|
||||
|
||||
if (ComplexityPolicyCheck(policyElement, pwNew, pwNewConfirmation) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return pwNew == pwNewConfirmation;
|
||||
}
|
||||
|
||||
let button = document.getElementById("init-button");
|
||||
disableSubmit(CheckInitPwPolicy, button);
|
||||
@@ -0,0 +1,14 @@
|
||||
const suffix = document.getElementById('default-login-suffix');
|
||||
const suffixInput = document.getElementsByClassName('lgn-suffix-input')[0];
|
||||
|
||||
if (suffix && suffixInput) {
|
||||
calculateOffset();
|
||||
suffix.addEventListener("DOMCharacterDataModified", calculateOffset);
|
||||
}
|
||||
|
||||
function calculateOffset() {
|
||||
// add suffix width to inner right padding of the input field
|
||||
if (suffix && suffixInput) {
|
||||
suffixInput.style.paddingRight = `${(suffix.offsetWidth ?? 0) + 10}px`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
autoSubmit();
|
||||
});
|
||||
|
||||
function autoSubmit() {
|
||||
let form = document.getElementsByTagName('form')[0];
|
||||
if (form) {
|
||||
let button = document.getElementById("redirect-button");
|
||||
if (button) {
|
||||
button.addEventListener("click", function (event) {
|
||||
location.reload();
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
function RenderDefaultLoginnameSuffix() {
|
||||
let orgNameText = document.getElementById("orgname").value;
|
||||
let userName = document.getElementById("username");
|
||||
let defaultLoginNameSuffix = document.getElementById("default-login-suffix");
|
||||
|
||||
let iamDomain = userName.dataset.iamDomain;
|
||||
let orgDomain = orgNameText.replace(" ", "-");
|
||||
if (orgDomain !== "") {
|
||||
defaultLoginNameSuffix.innerText = "@" + orgDomain.toLowerCase() + "." + iamDomain;
|
||||
} else {
|
||||
defaultLoginNameSuffix.innerText = "";
|
||||
}
|
||||
|
||||
offsetLabel();
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', (event) => {
|
||||
RenderDefaultLoginnameSuffix();
|
||||
});
|
||||
|
||||
document.getElementById("orgname").addEventListener('input', function () {
|
||||
RenderDefaultLoginnameSuffix();
|
||||
});
|
||||
|
||||
function offsetLabel() {
|
||||
const suffix = document.getElementById('default-login-suffix');
|
||||
const suffixInput = document.getElementsByClassName('lgn-suffix-input')[0];
|
||||
|
||||
calculateOffset();
|
||||
suffix.addEventListener("DOMCharacterDataModified", calculateOffset);
|
||||
|
||||
function calculateOffset() {
|
||||
// add suffix width to inner right padding of the input field
|
||||
if (suffix && suffixInput) {
|
||||
suffixInput.style.paddingRight = `${(suffix.offsetWidth ?? 0) + 10}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
function ComplexityPolicyCheck(policyElement, pwNew, pwNewConfirmation) {
|
||||
let minLength = policyElement.dataset.minlength;
|
||||
let upperRegex = policyElement.dataset.hasUppercase;
|
||||
let lowerRegex = policyElement.dataset.hasLowercase;
|
||||
let numberRegex = policyElement.dataset.hasNumber;
|
||||
let symbolRegex = policyElement.dataset.hasSymbol;
|
||||
|
||||
let valid = true;
|
||||
|
||||
let minlengthelem = document.getElementById('minlength');
|
||||
if (pwNew.length >= minLength) {
|
||||
ValidPolicy(minlengthelem);
|
||||
valid = true;
|
||||
} else {
|
||||
InvalidPolicy(minlengthelem);
|
||||
valid = false;
|
||||
}
|
||||
let upper = document.getElementById('uppercase');
|
||||
if (upperRegex !== "") {
|
||||
if (RegExp(upperRegex).test(pwNew)) {
|
||||
ValidPolicy(upper);
|
||||
valid = true;
|
||||
} else {
|
||||
InvalidPolicy(upper);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
let lower = document.getElementById('lowercase');
|
||||
if (lowerRegex !== "") {
|
||||
if (RegExp(lowerRegex).test(pwNew)) {
|
||||
ValidPolicy(lower);
|
||||
valid = true;
|
||||
} else {
|
||||
InvalidPolicy(lower);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
let number = document.getElementById('number');
|
||||
if (numberRegex != "") {
|
||||
if (RegExp(numberRegex).test(pwNew)) {
|
||||
ValidPolicy(number);
|
||||
valid = true;
|
||||
} else {
|
||||
InvalidPolicy(number);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
let symbol = document.getElementById('symbol');
|
||||
if (symbolRegex != "") {
|
||||
if (RegExp(symbolRegex).test(pwNew)) {
|
||||
ValidPolicy(symbol);
|
||||
valid = true;
|
||||
} else {
|
||||
InvalidPolicy(symbol);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
let confirmation = document.getElementById('confirmation');
|
||||
if (pwNew === pwNewConfirmation && pwNewConfirmation !== "" ) {
|
||||
ValidPolicy(confirmation);
|
||||
valid = true;
|
||||
} else {
|
||||
InvalidPolicy(confirmation);
|
||||
valid = false;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
function ValidPolicy(element) {
|
||||
element.classList.remove('invalid');
|
||||
element.getElementsByTagName('i')[0].classList.remove('lgn-icon-times-solid');
|
||||
element.getElementsByTagName('i')[0].classList.remove('lgn-warn');
|
||||
element.getElementsByTagName('i')[0].classList.add('lgn-icon-check-solid');
|
||||
element.getElementsByTagName('i')[0].classList.add('lgn-valid');
|
||||
}
|
||||
|
||||
function InvalidPolicy(element) {
|
||||
element.classList.add('invalid');
|
||||
element.getElementsByTagName('i')[0].classList.remove('lgn-valid');
|
||||
element.getElementsByTagName('i')[0].classList.remove('lgn-icon-check-solid');
|
||||
element.getElementsByTagName('i')[0].classList.add('lgn-warn');
|
||||
element.getElementsByTagName('i')[0].classList.add('lgn-icon-times-solid');
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
function CheckRegisterPwPolicy() {
|
||||
let policyElement = document.getElementById("register-password");
|
||||
let pwNew = policyElement.value;
|
||||
let pwNewConfirmation = document.getElementById("register-password-confirmation").value;
|
||||
|
||||
if (ComplexityPolicyCheck(policyElement, pwNew, pwNewConfirmation) === false) {
|
||||
policyElement.setAttribute("color", "warn");
|
||||
return false;
|
||||
} else {
|
||||
policyElement.setAttribute("color", "primary");
|
||||
}
|
||||
|
||||
return pwNew == pwNewConfirmation;
|
||||
}
|
||||
|
||||
let button = document.getElementById("register-button");
|
||||
disableSubmit(CheckRegisterPwPolicy, button);
|
||||
46
internal/api/ui/login/static/resources/scripts/theme.js
Normal file
46
internal/api/ui/login/static/resources/scripts/theme.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const usesDarkTheme = hasDarkModeOverwriteCookie() || (!hasLightModeOverwriteCookie() && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
if (usesDarkTheme) {
|
||||
document.documentElement.classList.replace('lgn-light-theme', 'lgn-dark-theme');
|
||||
writeModeCookie('dark');
|
||||
} else {
|
||||
document.documentElement.classList.replace('lgn-dark-theme', 'lgn-light-theme');
|
||||
writeModeCookie('light');
|
||||
}
|
||||
|
||||
function hasDarkModeOverwriteCookie() {
|
||||
return getCookie('mode') === 'dark';
|
||||
}
|
||||
|
||||
function hasLightModeOverwriteCookie() {
|
||||
return getCookie('mode') === 'light';
|
||||
}
|
||||
|
||||
function writeModeCookie(mode) {
|
||||
let cookieMode = getCookie('mode')
|
||||
if (cookieMode === '' || cookieMode.startsWith('auto')) {
|
||||
setCookie('mode', 'auto-' + mode, 365);
|
||||
}
|
||||
}
|
||||
|
||||
function getCookie(cname) {
|
||||
let name = cname + '=';
|
||||
let decodedCookie = decodeURIComponent(document.cookie);
|
||||
let ca = decodedCookie.split(';');
|
||||
for (let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) === ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) === 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function setCookie(name, value, exdays) {
|
||||
let d = new Date();
|
||||
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
|
||||
let expires = "expires=" + d.toUTCString();
|
||||
document.cookie = name + "=" + value + ";" + expires + ";path=/";
|
||||
}
|
||||
31
internal/api/ui/login/static/resources/scripts/webauthn.js
Normal file
31
internal/api/ui/login/static/resources/scripts/webauthn.js
Normal file
@@ -0,0 +1,31 @@
|
||||
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;
|
||||
}
|
||||
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');
|
||||
}
|
||||
|
||||
function bufferDecode(value) {
|
||||
return decode(value);
|
||||
}
|
||||
|
||||
function bufferEncode(value) {
|
||||
return encode(value)
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=/g, "");
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
document.addEventListener('DOMContentLoaded', checkWebauthnSupported('btn-login', login));
|
||||
|
||||
function login() {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
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 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();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
document.addEventListener('DOMContentLoaded', checkWebauthnSupported('btn-register', registerCredential));
|
||||
|
||||
function registerCredential() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 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();
|
||||
}
|
||||
Reference in New Issue
Block a user