Webauthn frontend code (#1411)

This commit is contained in:
Maxime Besson 2021-11-09 07:41:13 +01:00
parent 1054af21e4
commit 596e2f1f3d
34 changed files with 1179 additions and 20 deletions

View File

@ -27,9 +27,11 @@ delete2F = (device, epoch) ->
device = 'u'
else if device == 'UBK'
device = 'yubikey'
else if device == 'TOTP'
device = 'totp'
else setMsg 'u2fFailed', 'warning'
else if device == 'TOTP'
device = 'totp'
else if device == 'WebAuthn'
device = 'webauthn'
else setMsg 'u2fFailed', 'warning'
$.ajax
type: "POST"
url: "#{portal}2fregisters/#{device}/delete"

View File

@ -0,0 +1,30 @@
###
LemonLDAP::NG WebAuthn verify script
###
setMsg = (msg, level) ->
$('#msg').attr 'trspan', msg
$('#msg').html window.translate msg
$('#color').removeClass 'message-positive message-warning message-danger alert-success alert-warning alert-danger'
$('#color').addClass "message-#{level}"
level = 'success' if level == 'positive'
$('#color').addClass "alert-#{level}"
webAuthnError = (error) ->
switch (error.name)
when 'unsupported' then setMsg 'webAuthnUnsupported', 'warning'
else setMsg 'webAuthnBrowserFailed', 'danger'
check = ->
setMsg 'webAuthnBrowserInProgress', 'warning'
request = window.datas.request
WebAuthnUI.WebAuthnUI.getCredential request
. then (response) ->
$('#credential').val JSON.stringify response
$('#verify-form').submit()
. catch (error) ->
webAuthnError(error)
$(document).ready ->
setTimeout check, 1000
$('#retrybutton').on 'click', check

View File

@ -0,0 +1,97 @@
###
LemonLDAP::NG WebAuthn registration script
###
setMsg = (msg, level) ->
$('#msg').attr 'trspan', msg
$('#msg').html window.translate msg
$('#color').removeClass 'message-positive message-warning message-danger alert-success alert-warning alert-danger'
$('#color').addClass "message-#{level}"
level = 'success' if level == 'positive'
$('#color').addClass "alert-#{level}"
displayError = (j, status, err) ->
console.log 'Error', err
res = JSON.parse j.responseText
if res and res.error
res = res.error.replace(/.* /, '')
console.log 'Returned error', res
setMsg res, 'danger'
webAuthnError = (error) ->
switch (error.name)
when 'unsupported' then setMsg 'webAuthnUnsupported', 'warning'
else setMsg 'webAuthnBrowserFailed', 'danger'
# Registration function (launched by "register" button)
register = ->
# 1 get registration token
$.ajax
type: "POST",
url: "#{portal}2fregisters/webauthn/registrationchallenge"
data: {}
dataType: 'json'
error: displayError
success: (ch) ->
# 2 build response
request = ch.request
setMsg 'webAuthnRegisterInProgress', 'warning'
$('#u2fPermission').show()
WebAuthnUI.WebAuthnUI.createCredential request
. then (response) ->
$.ajax
type: "POST"
url: "#{portal}2fregisters/webauthn/registration"
data:
state_id: ch.state_id
credential: JSON.stringify response
keyName: $('#keyName').val()
dataType: 'json'
success: (resp) ->
if resp.error
if resp.error.match /badName/
setMsg resp.error, 'danger'
else setMsg 'webAuthnRegisterFailed', 'danger'
else if resp.result
setMsg 'yourKeyIsRegistered', 'positive'
error: displayError
. catch (error) ->
webAuthnError(error)
# Verification function (launched by "verify" button)
verify = ->
# 1 get challenge
$.ajax
type: "POST",
url: "#{portal}2fregisters/webauthn/verificationchallenge"
data: {}
dataType: 'json'
error: displayError
success: (ch) ->
# 2 build response
request = ch.request
setMsg 'webAuthnBrowserInProgress', 'warning'
WebAuthnUI.WebAuthnUI.getCredential request
. then (response) ->
$.ajax
type: "POST"
url: "#{portal}2fregisters/webauthn/verification"
data:
state_id: ch.state_id
credential: JSON.stringify response
dataType: 'json'
success: (resp) ->
if resp.error
setMsg 'webAuthnFailed', 'danger'
else if resp.result
setMsg 'yourKeyIsVerified', 'positive'
error: displayError
. catch (error) ->
webAuthnError(error)
# Register "click" events
$(document).ready ->
$('#u2fPermission').hide()
$('#register').on 'click', register
$('#verify').on 'click', verify
$('#goback').attr 'href', portal

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -40,6 +40,8 @@ LemonLDAP::NG 2F registration script
device = 'yubikey';
} else if (device === 'TOTP') {
device = 'totp';
} else if (device === 'WebAuthn') {
device = 'webauthn';
} else {
setMsg('u2fFailed', 'warning');
}

View File

@ -1 +1 @@
(function(){var e,t,n;n=function(e,r){return $("#msg").attr("trspan",e),$("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning alert-success alert-warning"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},t=function(e,r,t){var o;if(console.log("Error",t),(o=JSON.parse(e.responseText))&&o.error)return o=o.error.replace(/.* /,""),console.log("Returned error",o),o.match(/module/)?n("notAuthorized","warning"):n(o,"warning")},e=function(e,r){return"U2F"===e?e="u":"UBK"===e?e="yubikey":"TOTP"===e?e="totp":n("u2fFailed","warning"),$.ajax({type:"POST",url:portal+"2fregisters/"+e+"/delete",data:{epoch:r},dataType:"json",error:t,success:function(e){return e.error?e.error.match(/notAuthorized/)?n("notAuthorized","warning"):n("unknownAction","warning"):e.result?($("#delete-"+r).hide(),n("yourKeyIsUnregistered","positive")):void 0},error:t})},$(document).ready(function(){return $("body").on("click",".remove2f",function(){return e($(this).attr("device"),$(this).attr("epoch"))}),$("#goback").attr("href",portal),$(".data-epoch").each(function(){var e;return e=new Date(1e3*$(this).text()),$(this).text(e.toLocaleString())})})}).call(this);
!function(){var n=function(e,r){return $("#msg").attr("trspan",e),$("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning alert-success alert-warning"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},t=function(e,r,t){if(console.log("Error",t),(e=JSON.parse(e.responseText))&&e.error)return e=e.error.replace(/.* /,""),console.log("Returned error",e),e.match(/module/)?n("notAuthorized","warning"):n(e,"warning")},e=function(e,r){return"U2F"===e?e="u":"UBK"===e?e="yubikey":"TOTP"===e?e="totp":"WebAuthn"===e?e="webauthn":n("u2fFailed","warning"),$.ajax({type:"POST",url:portal+"2fregisters/"+e+"/delete",data:{epoch:r},dataType:"json",error:t,success:function(e){return e.error?e.error.match(/notAuthorized/)?n("notAuthorized","warning"):n("unknownAction","warning"):e.result?($("#delete-"+r).hide(),n("yourKeyIsUnregistered","positive")):void 0}})};$(document).ready(function(){return $("body").on("click",".remove2f",function(){return e($(this).attr("device"),$(this).attr("epoch"))}),$("#goback").attr("href",portal),$(".data-epoch").each(function(){var e=new Date(1e3*$(this).text());return $(this).text(e.toLocaleString())})})}.call(this);

View File

@ -1 +1 @@
{"version":3,"sources":["2fregistration.js"],"names":["delete2F","displayError","setMsg","msg","level","$","attr","html","window","translate","removeClass","addClass","j","status","err","res","console","log","JSON","parse","responseText","error","replace","match","device","epoch","ajax","type","url","portal","data","dataType","success","resp","result","hide","document","ready","on","this","each","myDate","Date","text","toLocaleString","call"],"mappings":"CAMA,WACE,IAAIA,EAAUC,EAAcC,EAE5BA,EAAS,SAASC,EAAKC,GAQrB,OAPAC,EAAE,QAAQC,KAAK,SAAUH,GACzBE,EAAE,QAAQE,KAAKC,OAAOC,UAAUN,IAChCE,EAAE,UAAUK,YAAY,gEACxBL,EAAE,UAAUM,SAAS,WAAaP,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUM,SAAS,SAAWP,IAGzCH,EAAe,SAASW,EAAGC,EAAQC,GACjC,IAAIC,EAGJ,GAFAC,QAAQC,IAAI,QAASH,IACrBC,EAAMG,KAAKC,MAAMP,EAAEQ,gBACRL,EAAIM,MAGb,OAFAN,EAAMA,EAAIM,MAAMC,QAAQ,MAAO,IAC/BN,QAAQC,IAAI,iBAAkBF,GAC1BA,EAAIQ,MAAM,UACLrB,EAAO,gBAAiB,WAExBA,EAAOa,EAAK,YAKzBf,EAAW,SAASwB,EAAQC,GAU1B,MATe,QAAXD,EACFA,EAAS,IACW,QAAXA,EACTA,EAAS,UACW,SAAXA,EACTA,EAAS,OAETtB,EAAO,YAAa,WAEfG,EAAEqB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,eAAiBL,EAAS,UACxCM,KAAM,CACJL,MAAOA,GAETM,SAAU,OACVV,MAAOpB,EACP+B,QAAS,SAASC,GAChB,OAAIA,EAAKZ,MACHY,EAAKZ,MAAME,MAAM,iBACZrB,EAAO,gBAAiB,WAExBA,EAAO,gBAAiB,WAExB+B,EAAKC,QACd7B,EAAE,WAAaoB,GAAOU,OACfjC,EAAO,wBAAyB,kBAFlC,GAKTmB,MAAOpB,KAIXI,EAAE+B,UAAUC,MAAM,WAKhB,OAJAhC,EAAE,QAAQiC,GAAG,QAAS,YAAa,WACjC,OAAOtC,EAASK,EAAEkC,MAAMjC,KAAK,UAAWD,EAAEkC,MAAMjC,KAAK,YAEvDD,EAAE,WAAWC,KAAK,OAAQuB,QACnBxB,EAAE,eAAemC,KAAK,WAC3B,IAAIC,EAEJ,OADAA,EAAS,IAAIC,KAAsB,IAAjBrC,EAAEkC,MAAMI,QACnBtC,EAAEkC,MAAMI,KAAKF,EAAOG,wBAI9BC,KAAKN"}
{"version":3,"sources":["2fregistration.js"],"names":["setMsg","msg","level","$","attr","html","window","translate","removeClass","addClass","displayError","j","status","err","console","log","res","JSON","parse","responseText","error","replace","match","delete2F","device","epoch","ajax","type","url","portal","data","dataType","success","resp","result","hide","document","ready","on","this","each","myDate","Date","text","toLocaleString","call"],"mappings":"CAMA,WACE,IAEAA,EAAS,SAASC,EAAKC,GAQrB,OAPAC,EAAE,QAAQC,KAAK,SAAUH,GACzBE,EAAE,QAAQE,KAAKC,OAAOC,UAAUN,IAChCE,EAAE,UAAUK,YAAY,gEACxBL,EAAE,UAAUM,SAAS,WAAaP,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUM,SAAS,SAAWP,IAGzCQ,EAAe,SAASC,EAAGC,EAAQC,GAIjC,GAFAC,QAAQC,IAAI,QAASF,IACrBG,EAAMC,KAAKC,MAAMP,EAAEQ,gBACRH,EAAII,MAGb,OAFAJ,EAAMA,EAAII,MAAMC,QAAQ,MAAO,IAC/BP,QAAQC,IAAI,iBAAkBC,GAC1BA,EAAIM,MAAM,UACLtB,EAAO,gBAAiB,WAExBA,EAAOgB,EAAK,YAKzBO,EAAW,SAASC,EAAQC,GAY1B,MAXe,QAAXD,EACFA,EAAS,IACW,QAAXA,EACTA,EAAS,UACW,SAAXA,EACTA,EAAS,OACW,aAAXA,EACTA,EAAS,WAETxB,EAAO,YAAa,WAEfG,EAAEuB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,eAAiBL,EAAS,UACxCM,KAAM,CACJL,MAAOA,GAETM,SAAU,OANEX,MAoBLV,EAZPsB,QAAS,SAASC,GAChB,OAAIA,EAAKb,MACHa,EAAKb,MAAME,MAAM,iBACZtB,EAAO,gBAAiB,WAExBA,EAAO,gBAAiB,WAExBiC,EAAKC,QACd/B,EAAE,WAAasB,GAAOU,OACfnC,EAAO,wBAAyB,kBAFlC,MASbG,EAAEiC,UAAUC,MAAM,WAKhB,OAJAlC,EAAE,QAAQmC,GAAG,QAAS,YAAa,WACjC,OAAOf,EAASpB,EAAEoC,MAAMnC,KAAK,UAAWD,EAAEoC,MAAMnC,KAAK,YAEvDD,EAAE,WAAWC,KAAK,OAAQyB,QACnB1B,EAAE,eAAeqC,KAAK,WAC3B,IACAC,EAAS,IAAIC,KAAsB,IAAjBvC,EAAEoC,MAAMI,QAC1B,OAAOxC,EAAEoC,MAAMI,KAAKF,EAAOG,uBAI9BC,KAAKN"}

View File

@ -0,0 +1,561 @@
/*! webauthn-ui library (C) 2018 - 2020 Thomas Bleeker (www.madwizard.org) - MIT license */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.WebAuthnUI = {}));
}(this, (function (exports) { 'use strict';
/* Microsoft tslib 0BSD licensed */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
function waitReadyState(alreadyDone, eventDispatcher, eventName) {
if (alreadyDone) {
return Promise.resolve();
}
return new Promise(function (resolve) {
var readyFunc = function () {
eventDispatcher.removeEventListener(eventName, readyFunc);
resolve();
};
eventDispatcher.addEventListener(eventName, readyFunc);
});
}
function ready() {
return waitReadyState(document.readyState !== 'loading', document, 'DOMContentLoaded');
}
function loaded() {
return waitReadyState(document.readyState === 'complete', window, 'load');
}
var WebAuthnError = /** @class */ (function (_super) {
__extends(WebAuthnError, _super);
function WebAuthnError(name, message, innerError) {
var _newTarget = this.constructor;
var _this = _super.call(this, "WebAuthnUI error: " + (message !== undefined ? message : name)) || this;
Object.setPrototypeOf(_this, _newTarget.prototype); // restore prototype chain
_this.name = name;
_this.innerError = innerError;
return _this;
}
WebAuthnError.fromError = function (error) {
var type = 'unknown';
var message;
if (error instanceof DOMException) {
var map = {
NotAllowedError: 'dom-not-allowed',
SecurityError: 'dom-security',
NotSupportedError: 'dom-not-supported',
AbortError: 'dom-abort',
InvalidStateError: 'dom-invalid-state',
};
type = map[error.name] || 'dom-unknown';
message = type;
}
else {
message = "unknown (" + error.toString() + ")";
}
return new WebAuthnError(type, message, error instanceof Error ? error : undefined);
};
return WebAuthnError;
}(Error));
function encode(arraybuffer) {
var buffer = new Uint8Array(arraybuffer);
var binary = '';
for (var i_1 = 0; i_1 < buffer.length; i_1++) {
binary += String.fromCharCode(buffer[i_1]);
}
var encoded = window.btoa(binary);
var i = encoded.length - 1;
while (i > 0 && encoded[i] === '=') {
i--;
}
encoded = encoded.substr(0, i + 1);
encoded = encoded.replace(/\+/g, '-').replace(/\//g, '_');
return encoded;
}
function decode(base64) {
var converted = base64.replace(/-/g, '+').replace(/_/g, '/');
switch (converted.length % 4) {
case 2:
converted += '==';
break;
case 3:
converted += '=';
break;
case 1:
throw new WebAuthnError('parse-error');
}
var bin = window.atob(converted);
var buffer = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i);
}
return buffer;
}
function map(src, mapper) {
var dest = {};
var keys = Object.keys(mapper);
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
var action = mapper[k];
var val = src[k];
if (val !== undefined) {
if (action === 0 /* Copy */) {
dest[k] = val;
}
else if (action === 1 /* Base64Decode */) {
dest[k] = val === null ? null : decode(val);
}
else if (action === 2 /* Base64Encode */) {
dest[k] = val === null ? null : encode(val);
}
else if (typeof action === 'object') {
dest[k] = map(val, action);
}
else {
dest[k] = action(val);
}
}
}
return dest;
}
function arrayMap(mapper) {
return function (src) {
var dest = [];
for (var i = 0; i < src.length; i++) {
dest[i] = map(src[i], mapper);
}
return dest;
};
}
function getCredentialDescListMap() {
return arrayMap({
type: 0 /* Copy */,
id: 1 /* Base64Decode */,
transports: 0 /* Copy */,
});
}
function addExtensionOutputs(dest, pkc) {
var clientExtensionResults = pkc.getClientExtensionResults();
if (Object.keys(clientExtensionResults).length > 0) {
dest.clientExtensionResults = map(clientExtensionResults, {
appid: 0 /* Copy */,
});
}
}
var Converter = /** @class */ (function () {
function Converter() {
}
Converter.convertCreationOptions = function (options) {
return map(options, {
rp: 0 /* Copy */,
user: {
id: 1 /* Base64Decode */,
name: 0 /* Copy */,
displayName: 0 /* Copy */,
icon: 0 /* Copy */,
},
challenge: 1 /* Base64Decode */,
pubKeyCredParams: 0 /* Copy */,
timeout: 0 /* Copy */,
excludeCredentials: getCredentialDescListMap(),
authenticatorSelection: 0 /* Copy */,
attestation: 0 /* Copy */,
extensions: {
appid: 0 /* Copy */,
},
});
};
Converter.convertCreationResponse = function (pkc) {
var response = map(pkc, {
type: 0 /* Copy */,
id: 0 /* Copy */,
rawId: 2 /* Base64Encode */,
response: {
clientDataJSON: 2 /* Base64Encode */,
attestationObject: 2 /* Base64Encode */,
},
});
addExtensionOutputs(response, pkc);
return response;
};
Converter.convertRequestOptions = function (options) {
return map(options, {
challenge: 1 /* Base64Decode */,
timeout: 0 /* Copy */,
rpId: 0 /* Copy */,
allowCredentials: getCredentialDescListMap(),
userVerification: 0 /* Copy */,
extensions: {
appid: 0 /* Copy */,
},
});
};
Converter.convertRequestResponse = function (pkc) {
var response = map(pkc, {
type: 0 /* Copy */,
id: 0 /* Copy */,
rawId: 2 /* Base64Encode */,
response: {
clientDataJSON: 2 /* Base64Encode */,
authenticatorData: 2 /* Base64Encode */,
signature: 2 /* Base64Encode */,
userHandle: 2 /* Base64Encode */,
},
});
addExtensionOutputs(response, pkc);
return response;
};
return Converter;
}());
var loadEvents = { loaded: loaded, ready: ready };
function elementSelector(selector) {
var items;
if (typeof selector === 'string') {
items = document.querySelectorAll(selector);
}
else {
items = [selector];
}
return items;
}
var WebAuthnUI = /** @class */ (function () {
function WebAuthnUI() {
}
WebAuthnUI.isSupported = function () {
return typeof window.PublicKeyCredential !== 'undefined';
};
WebAuthnUI.isUVPASupported = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (this.isSupported()) {
return [2 /*return*/, window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()];
}
return [2 /*return*/, false];
});
});
};
WebAuthnUI.checkSupport = function () {
if (!WebAuthnUI.isSupported()) {
throw new WebAuthnError('unsupported');
}
};
WebAuthnUI.createCredential = function (options) {
return __awaiter(this, void 0, void 0, function () {
var request, credential, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
WebAuthnUI.checkSupport();
request = {
publicKey: Converter.convertCreationOptions(options),
};
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, navigator.credentials.create(request)];
case 2:
credential = (_a.sent());
return [3 /*break*/, 4];
case 3:
e_1 = _a.sent();
throw WebAuthnError.fromError(e_1);
case 4: return [2 /*return*/, Converter.convertCreationResponse(credential)];
}
});
});
};
WebAuthnUI.getCredential = function (options) {
return __awaiter(this, void 0, void 0, function () {
var request, credential, e_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
WebAuthnUI.checkSupport();
request = {
publicKey: Converter.convertRequestOptions(options),
};
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, navigator.credentials.get(request)];
case 2:
credential = (_a.sent());
return [3 /*break*/, 4];
case 3:
e_2 = _a.sent();
throw WebAuthnError.fromError(e_2);
case 4: return [2 /*return*/, Converter.convertRequestResponse(credential)];
}
});
});
};
WebAuthnUI.setFeatureCssClasses = function (selector) {
return __awaiter(this, void 0, void 0, function () {
var items, applyClass;
return __generator(this, function (_a) {
items = elementSelector(selector);
applyClass = function (cls) {
for (var i = 0; i < items.length; i++) {
items[i].classList.add(cls);
}
};
applyClass("webauthn-" + (WebAuthnUI.isSupported() ? '' : 'un') + "supported");
return [2 /*return*/, WebAuthnUI.isUVPASupported().then(function (available) {
applyClass("webauthn-uvpa-" + (available ? '' : 'un') + "supported");
})];
});
});
};
WebAuthnUI.loadConfig = function (config) {
return __awaiter(this, void 0, void 0, function () {
var field, el, submit, response, newField;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
// Wait for DOM ready
return [4 /*yield*/, ready()];
case 1:
// Wait for DOM ready
_a.sent();
field = config.formField;
if (typeof field === 'string') {
el = document.querySelector(field);
if (el === null) {
throw new WebAuthnError('bad-config', 'Could not find formField.');
}
field = el;
}
if (!(field instanceof HTMLInputElement || field instanceof HTMLTextAreaElement)) {
throw new WebAuthnError('bad-config', 'formField does not refer to an input element.');
}
submit = config.submitForm !== false;
if (!this.isSupported() && config.postUnsupportedImmediately === true) {
response = { status: 'failed', error: 'unsupported' };
this.setForm(field, response, submit);
return [2 /*return*/, response];
}
newField = field;
return [2 /*return*/, new Promise(function (resolve) {
var trigger = config.trigger;
var resolved = false;
if (trigger.event === 'click') {
var targets = elementSelector(config.trigger.element);
var handler = function () { return __awaiter(_this, void 0, void 0, function () {
var response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.runAutoConfig(config)];
case 1:
response = _a.sent();
this.setForm(newField, response, submit);
if (!resolved) {
resolved = true;
resolve(response);
}
return [2 /*return*/];
}
});
}); };
for (var i = 0; i < targets.length; i++) {
targets[i].addEventListener('click', handler);
}
}
else {
throw new WebAuthnError('bad-config');
}
})];
}
});
});
};
WebAuthnUI.startConfig = function (config) {
return __awaiter(this, void 0, void 0, function () {
var credential;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(config.type === 'get')) return [3 /*break*/, 2];
return [4 /*yield*/, this.getCredential(config.request)];
case 1:
credential = _a.sent();
return [3 /*break*/, 5];
case 2:
if (!(config.type === 'create')) return [3 /*break*/, 4];
return [4 /*yield*/, this.createCredential(config.request)];
case 3:
credential = _a.sent();
return [3 /*break*/, 5];
case 4: throw new WebAuthnError('bad-config', "Invalid config.type " + config.type);
case 5: return [2 /*return*/, {
status: 'ok',
credential: credential,
}];
}
});
});
};
WebAuthnUI.runAutoConfig = function (config) {
return __awaiter(this, void 0, void 0, function () {
var response, e_3, waError;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
return [4 /*yield*/, this.startConfig(config)];
case 1:
response = _a.sent();
return [3 /*break*/, 3];
case 2:
e_3 = _a.sent();
waError = (e_3 instanceof WebAuthnError);
if (config.debug === true) {
console.error(e_3); // eslint-disable-line no-console
if (waError && e_3.innerError) {
console.error(e_3.innerError); // eslint-disable-line no-console
}
}
response = {
status: 'failed',
error: (waError ? e_3.name : WebAuthnError.fromError(e_3).name),
};
return [3 /*break*/, 3];
case 3: return [2 /*return*/, response];
}
});
});
};
WebAuthnUI.setForm = function (field, response, submit) {
field.value = JSON.stringify(response);
if (submit && field.form) {
field.form.submit();
}
};
WebAuthnUI.autoConfig = function () {
return __awaiter(this, void 0, void 0, function () {
var promises, list, i, el, isScript, rawJson, json;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
promises = [];
list = document.querySelectorAll('input[data-webauthn],textarea[data-webauthn],script[data-webauthn]');
for (i = 0; i < list.length; i++) {
el = list[i];
isScript = el.tagName === 'SCRIPT';
if (isScript && el.type !== 'application/json') {
throw new WebAuthnError('bad-config', 'Expecting application/json script with data-webauthn');
}
rawJson = isScript ? el.textContent : (el).getAttribute('data-webauthn');
if (rawJson === null) {
throw new WebAuthnError('bad-config', 'Missing JSON in data-webauthn');
}
json = void 0;
try {
json = JSON.parse(rawJson);
}
catch (e) {
throw new WebAuthnError('bad-config', 'invalid JSON in data-webauthn on element');
}
if (!isScript && json.formField === undefined) {
json.formField = el;
}
promises.push(this.loadConfig(json));
}
return [4 /*yield*/, Promise.all(promises)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
WebAuthnUI.inProgress = false;
return WebAuthnUI;
}());
function auto() {
return __awaiter(this, void 0, void 0, function () {
var list, i;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, ready()];
case 1:
_a.sent();
list = document.querySelectorAll('.webauthn-detect');
for (i = 0; i < list.length; i++) {
WebAuthnUI.setFeatureCssClasses(list[i]);
}
return [2 /*return*/, WebAuthnUI.autoConfig()];
}
});
});
}
var autoPromise = auto().catch(function (e) {
if (console && console.error) { // eslint-disable-line no-console
console.error(e); // eslint-disable-line no-console
}
});
exports.WebAuthnError = WebAuthnError;
exports.WebAuthnUI = WebAuthnUI;
exports.autoPromise = autoPromise;
exports.loadEvents = loadEvents;
Object.defineProperty(exports, '__esModule', { value: true });
})));

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,47 @@
// Generated by CoffeeScript 1.12.8
/*
LemonLDAP::NG WebAuthn verify script
*/
(function() {
var check, setMsg, webAuthnError;
setMsg = function(msg, level) {
$('#msg').attr('trspan', msg);
$('#msg').html(window.translate(msg));
$('#color').removeClass('message-positive message-warning message-danger alert-success alert-warning alert-danger');
$('#color').addClass("message-" + level);
if (level === 'positive') {
level = 'success';
}
return $('#color').addClass("alert-" + level);
};
webAuthnError = function(error) {
switch (error.name) {
case 'unsupported':
return setMsg('webAuthnUnsupported', 'warning');
default:
return setMsg('webAuthnBrowserFailed', 'danger');
}
};
check = function() {
var request;
setMsg('webAuthnBrowserInProgress', 'warning');
request = window.datas.request;
return WebAuthnUI.WebAuthnUI.getCredential(request).then(function(response) {
$('#credential').val(JSON.stringify(response));
return $('#verify-form').submit();
})["catch"](function(error) {
return webAuthnError(error);
});
};
$(document).ready(function() {
setTimeout(check, 1000);
return $('#retrybutton').on('click', check);
});
}).call(this);

View File

@ -0,0 +1 @@
!function(){var n=function(e,n){return $("#msg").attr("trspan",e),$("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+n),"positive"===n&&(n="success"),$("#color").addClass("alert-"+n)},r=function(e){return"unsupported"!==e.name?n("webAuthnBrowserFailed","danger"):n("webAuthnUnsupported","warning")},e=function(){var e;return n("webAuthnBrowserInProgress","warning"),e=window.datas.request,WebAuthnUI.WebAuthnUI.getCredential(e).then(function(e){return $("#credential").val(JSON.stringify(e)),$("#verify-form").submit()}).catch(r)};$(document).ready(function(){return setTimeout(e,1e3),$("#retrybutton").on("click",e)})}.call(this);

View File

@ -0,0 +1 @@
{"version":3,"sources":["webauthncheck.js"],"names":["setMsg","msg","level","$","attr","html","window","translate","removeClass","addClass","webAuthnError","error","name","check","request","datas","WebAuthnUI","getCredential","then","response","val","JSON","stringify","submit","document","ready","setTimeout","on","call","this"],"mappings":"CAMA,WACE,IAEAA,EAAS,SAASC,EAAKC,GAQrB,OAPAC,EAAE,QAAQC,KAAK,SAAUH,GACzBE,EAAE,QAAQE,KAAKC,OAAOC,UAAUN,IAChCE,EAAE,UAAUK,YAAY,4FACxBL,EAAE,UAAUM,SAAS,WAAaP,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUM,SAAS,SAAWP,IAGzCQ,EAAgB,SAASC,GACvB,MACO,gBADCA,EAAMC,KAIHZ,EAAO,wBAAyB,UAFhCA,EAAO,sBAAuB,YAM3Ca,EAAQ,WACN,IAAIC,EAGJ,OAFAd,EAAO,4BAA6B,WACpCc,EAAUR,OAAOS,MAAMD,QAChBE,WAAWA,WAAWC,cAAcH,GAASI,KAAK,SAASC,GAEhE,OADAhB,EAAE,eAAeiB,IAAIC,KAAKC,UAAUH,IAC7BhB,EAAE,gBAAgBoB,WACjB,MACDb,IAIXP,EAAEqB,UAAUC,MAAM,WAEhB,OADAC,WAAWb,EAAO,KACXV,EAAE,gBAAgBwB,GAAG,QAASd,MAGtCe,KAAKC"}

View File

@ -0,0 +1,126 @@
// Generated by CoffeeScript 1.12.8
/*
LemonLDAP::NG WebAuthn registration script
*/
(function() {
var displayError, register, setMsg, verify, webAuthnError;
setMsg = function(msg, level) {
$('#msg').attr('trspan', msg);
$('#msg').html(window.translate(msg));
$('#color').removeClass('message-positive message-warning message-danger alert-success alert-warning alert-danger');
$('#color').addClass("message-" + level);
if (level === 'positive') {
level = 'success';
}
return $('#color').addClass("alert-" + level);
};
displayError = function(j, status, err) {
var res;
console.log('Error', err);
res = JSON.parse(j.responseText);
if (res && res.error) {
res = res.error.replace(/.* /, '');
console.log('Returned error', res);
return setMsg(res, 'danger');
}
};
webAuthnError = function(error) {
switch (error.name) {
case 'unsupported':
return setMsg('webAuthnUnsupported', 'warning');
default:
return setMsg('webAuthnBrowserFailed', 'danger');
}
};
register = function() {
return $.ajax({
type: "POST",
url: portal + "2fregisters/webauthn/registrationchallenge",
data: {},
dataType: 'json',
error: displayError,
success: function(ch) {
var request;
request = ch.request;
setMsg('webAuthnRegisterInProgress', 'warning');
$('#u2fPermission').show();
return WebAuthnUI.WebAuthnUI.createCredential(request).then(function(response) {
return $.ajax({
type: "POST",
url: portal + "2fregisters/webauthn/registration",
data: {
state_id: ch.state_id,
credential: JSON.stringify(response),
keyName: $('#keyName').val()
},
dataType: 'json',
success: function(resp) {
if (resp.error) {
if (resp.error.match(/badName/)) {
return setMsg(resp.error, 'danger');
} else {
return setMsg('webAuthnRegisterFailed', 'danger');
}
} else if (resp.result) {
return setMsg('yourKeyIsRegistered', 'positive');
}
},
error: displayError
});
})["catch"](function(error) {
return webAuthnError(error);
});
}
});
};
verify = function() {
return $.ajax({
type: "POST",
url: portal + "2fregisters/webauthn/verificationchallenge",
data: {},
dataType: 'json',
error: displayError,
success: function(ch) {
var request;
request = ch.request;
setMsg('webAuthnBrowserInProgress', 'warning');
return WebAuthnUI.WebAuthnUI.getCredential(request).then(function(response) {
return $.ajax({
type: "POST",
url: portal + "2fregisters/webauthn/verification",
data: {
state_id: ch.state_id,
credential: JSON.stringify(response)
},
dataType: 'json',
success: function(resp) {
if (resp.error) {
return setMsg('webAuthnFailed', 'danger');
} else if (resp.result) {
return setMsg('yourKeyIsVerified', 'positive');
}
},
error: displayError
});
})["catch"](function(error) {
return webAuthnError(error);
});
}
});
};
$(document).ready(function() {
$('#u2fPermission').hide();
$('#register').on('click', register);
$('#verify').on('click', verify);
return $('#goback').attr('href', portal);
});
}).call(this);

View File

@ -0,0 +1 @@
!function(){var n=function(e,r){return $("#msg").attr("trspan",e),$("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},t=function(e,r,t){if(console.log("Error",t),(e=JSON.parse(e.responseText))&&e.error)return e=e.error.replace(/.* /,""),console.log("Returned error",e),n(e,"danger")},a=function(e){return"unsupported"!==e.name?n("webAuthnBrowserFailed","danger"):n("webAuthnUnsupported","warning")},e=function(){return $.ajax({type:"POST",url:portal+"2fregisters/webauthn/registrationchallenge",data:{},dataType:"json",error:t,success:function(r){var e=r.request;return n("webAuthnRegisterInProgress","warning"),$("#u2fPermission").show(),WebAuthnUI.WebAuthnUI.createCredential(e).then(function(e){return $.ajax({type:"POST",url:portal+"2fregisters/webauthn/registration",data:{state_id:r.state_id,credential:JSON.stringify(e),keyName:$("#keyName").val()},dataType:"json",success:function(e){return e.error?e.error.match(/badName/)?n(e.error,"danger"):n("webAuthnRegisterFailed","danger"):e.result?n("yourKeyIsRegistered","positive"):void 0},error:t})}).catch(a)}})},r=function(){return $.ajax({type:"POST",url:portal+"2fregisters/webauthn/verificationchallenge",data:{},dataType:"json",error:t,success:function(r){var e=r.request;return n("webAuthnBrowserInProgress","warning"),WebAuthnUI.WebAuthnUI.getCredential(e).then(function(e){return $.ajax({type:"POST",url:portal+"2fregisters/webauthn/verification",data:{state_id:r.state_id,credential:JSON.stringify(e)},dataType:"json",success:function(e){return e.error?n("webAuthnFailed","danger"):e.result?n("yourKeyIsVerified","positive"):void 0},error:t})}).catch(a)}})};$(document).ready(function(){return $("#u2fPermission").hide(),$("#register").on("click",e),$("#verify").on("click",r),$("#goback").attr("href",portal)})}.call(this);

View File

@ -0,0 +1 @@
{"version":3,"sources":["webauthnregistration.js"],"names":["setMsg","msg","level","$","attr","html","window","translate","removeClass","addClass","displayError","j","status","err","console","log","res","JSON","parse","responseText","error","replace","webAuthnError","name","register","ajax","type","url","portal","data","dataType","success","ch","request","show","WebAuthnUI","createCredential","then","response","state_id","credential","stringify","keyName","val","resp","match","result","verify","getCredential","document","ready","hide","on","call","this"],"mappings":"CAMA,WACE,IAEAA,EAAS,SAASC,EAAKC,GAQrB,OAPAC,EAAE,QAAQC,KAAK,SAAUH,GACzBE,EAAE,QAAQE,KAAKC,OAAOC,UAAUN,IAChCE,EAAE,UAAUK,YAAY,4FACxBL,EAAE,UAAUM,SAAS,WAAaP,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUM,SAAS,SAAWP,IAGzCQ,EAAe,SAASC,EAAGC,EAAQC,GAIjC,GAFAC,QAAQC,IAAI,QAASF,IACrBG,EAAMC,KAAKC,MAAMP,EAAEQ,gBACRH,EAAII,MAGb,OAFAJ,EAAMA,EAAII,MAAMC,QAAQ,MAAO,IAC/BP,QAAQC,IAAI,iBAAkBC,GACvBhB,EAAOgB,EAAK,WAIvBM,EAAgB,SAASF,GACvB,MACO,gBADCA,EAAMG,KAIHvB,EAAO,wBAAyB,UAFhCA,EAAO,sBAAuB,YAM3CwB,EAAW,WACT,OAAOrB,EAAEsB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,6CACdC,KAAM,GACNC,SAAU,OACVV,MAAOV,EACPqB,QAAS,SAASC,GAChB,IACAC,EAAUD,EAAGC,QAGb,OAFAjC,EAAO,6BAA8B,WACrCG,EAAE,kBAAkB+B,OACbC,WAAWA,WAAWC,iBAAiBH,GAASI,KAAK,SAASC,GACnE,OAAOnC,EAAEsB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,oCACdC,KAAM,CACJU,SAAUP,EAAGO,SACbC,WAAYvB,KAAKwB,UAAUH,GAC3BI,QAASvC,EAAE,YAAYwC,OAEzBb,SAAU,OACVC,QAAS,SAASa,GAChB,OAAIA,EAAKxB,MACHwB,EAAKxB,MAAMyB,MAAM,WACZ7C,EAAO4C,EAAKxB,MAAO,UAEnBpB,EAAO,yBAA0B,UAEjC4C,EAAKE,OACP9C,EAAO,sBAAuB,iBADhC,GAIToB,MAAOV,MAED,MACDY,OAMfyB,EAAS,WACP,OAAO5C,EAAEsB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,6CACdC,KAAM,GACNC,SAAU,OACVV,MAAOV,EACPqB,QAAS,SAASC,GAChB,IACAC,EAAUD,EAAGC,QAEb,OADAjC,EAAO,4BAA6B,WAC7BmC,WAAWA,WAAWa,cAAcf,GAASI,KAAK,SAASC,GAChE,OAAOnC,EAAEsB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,oCACdC,KAAM,CACJU,SAAUP,EAAGO,SACbC,WAAYvB,KAAKwB,UAAUH,IAE7BR,SAAU,OACVC,QAAS,SAASa,GAChB,OAAIA,EAAKxB,MACApB,EAAO,iBAAkB,UACvB4C,EAAKE,OACP9C,EAAO,oBAAqB,iBAD9B,GAIToB,MAAOV,MAED,MACDY,OAMfnB,EAAE8C,UAAUC,MAAM,WAIhB,OAHA/C,EAAE,kBAAkBgD,OACpBhD,EAAE,aAAaiD,GAAG,QAAS5B,GAC3BrB,EAAE,WAAWiD,GAAG,QAASL,GAClB5C,EAAE,WAAWC,KAAK,OAAQwB,WAGlCyB,KAAKC"}

View File

@ -270,6 +270,7 @@
"resentConfirm":"هل تريد إعادة إرسال رسالة التأكيد؟",
"resetPwd":"إعادة تعيين كلمة المرور الخاصة بي",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":" إعادة تحميل الحقوق تحتاج إلى تسجيل الخروج وتسجيل الدخول مرة أخرى",
"rules":"RULES",
"scope":"نطاق",
@ -320,6 +321,16 @@
"wait":"انتظر",
"waitingmessage":"Authentication in progress, please wait",
"warning":"تحذير",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"مرحبا بك على بوابة إثبات الهوية الآمنة.",
"yesResendMail":"نعم، أعد إرسال البريد",
"yourAddress":"Know your address",
@ -337,4 +348,4 @@
"yourProfile":"Know your profile",
"yourTotpKey":"Your TOTP key",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Möchtest du, dass die Bestätigungsmail erneut gesendet wird ?",
"resetPwd":"Mein Passwort zurücksetzen",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":"Zum Neuladen der Rechte musst du dich ab- und wieder anmelden",
"rules":"RULES",
"scope":"Scope",
@ -320,6 +321,16 @@
"wait":"Warten",
"waitingmessage":"Authentication in progress, please wait",
"warning":"Warnung",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Willkommen in Ihrem gesicherten Authentifizierungsportal.",
"yesResendMail":"Ja, Mail erneut senden.",
"yourAddress":"Know your address",
@ -337,4 +348,4 @@
"yourProfile":"Know your profile",
"yourTotpKey":"Your TOTP key",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetPwd":"Reset my password",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"rules":"RULES",
"scope":"Scope",
@ -320,6 +321,16 @@
"wait":"Wait",
"waitingmessage":"Authentication in progress, please wait",
"warning":"Warning",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Welcome on your secured authentication portal.",
"yesResendMail":"Yes, resend the mail",
"yourAddress":"Know your address",

View File

@ -270,6 +270,7 @@
"resentConfirm":"¿Desea que el e-mail de confirmación sea reenviado?",
"resetPwd":"Reiniciar mi contraseña",
"rest2f":"Código de verificación",
"retry":"Retry",
"rightsReloadNeedsLogout":"La recarga de derechos necesita desconectarse y conectarse de nuevo",
"rules":"RULES",
"scope":"Alcance",
@ -320,6 +321,16 @@
"wait":"Esperar",
"waitingmessage":"Autenticación en progreso, espere por favor",
"warning":"Precaución",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Bienvenido a su portal de autenticación.",
"yesResendMail":"Sí, reenviar el e-mail",
"yourAddress":"Conozca su dirección",
@ -337,4 +348,4 @@
"yourProfile":"Conozca su perfil",
"yourTotpKey":"Su llave TOTP",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetPwd":"Palauta salasanani?",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"rules":"RULES",
"scope":"Scope",
@ -320,6 +321,16 @@
"wait":"Odota",
"waitingmessage":"Authentication in progress, please wait",
"warning":"Varoitus",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Welcome on your secured authentication portal.",
"yesResendMail":"Kyllä, uudelleen lähetä sähköposti",
"yourAddress":"Know your address",
@ -337,4 +348,4 @@
"yourProfile":"Know your profile",
"yourTotpKey":"Your TOTP key",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Voulez-vous que le message de confirmation soit renvoyé ?",
"resetPwd":"Réinitialiser mon mot de passe",
"rest2f":"Code de vérification",
"retry":"Réessayer",
"rightsReloadNeedsLogout":"Le rechargement des droits nécessite une déconnexion",
"rules":"REGLES",
"scope":"Informations",
@ -320,6 +321,16 @@
"wait":"Attendre",
"waitingmessage":"Authentification en cours, merci de patienter",
"warning":"Attention",
"webAuthnBrowserFailed":"Le navigateur n'a pas pu obtenir d'assertion WebAuthn",
"webAuthnBrowserInProgress":"Authentification WebAuthn en cours, veuillez suivre les instructions de votre navigateur",
"webAuthnFailed":"L'authentification WebAuthn a échoué",
"webAuthnRegisterFailed":"L'enregistrement WebAuthn a échoué",
"webAuthnRegisterInProgress":"Enregistrement WebAuthn en cours, veuillez suivre les instructions de votre navigateur",
"webAuthnRequired":"Authentification WebAuthn nécessaire",
"webAuthnUnsupported":"Votre navigateur ne supporte pas WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Enregistrement d'un périphérique de sécurité",
"webauthnAlreadyRegistered":"Ce périphérique est déjà enregistré",
"welcomeOnPortal":"Bienvenue sur votre portail d'authentification sécurisée.",
"yesResendMail":"Oui, renvoyer le mail",
"yourAddress":"Connaître votre adresse",

View File

@ -270,6 +270,7 @@
"resentConfirm":"האם לשלוח שוב את הודעת האימות בדוא״ל?",
"resetPwd":"איפוס הסיסמה שלי",
"rest2f":"קוד אימות",
"retry":"Retry",
"rightsReloadNeedsLogout":"רענוני זכויות דורשים יציאה וכניסה מחדש",
"rules":"כללים",
"scope":"היקף",
@ -320,6 +321,16 @@
"wait":"המתנה",
"waitingmessage":"מתבצע אימות, נא להמתין",
"warning":"אזהרה",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"ברוך בואך לשער האימות המאובטח שלך.",
"yesResendMail":"כן, לשלוח את ההודעה שוב",
"yourAddress":"היכרות עם הכתובת שלך",
@ -337,4 +348,4 @@
"yourProfile":"היכרות עם הפרופיל שלך",
"yourTotpKey":"מפתח ה־TOTP שלך",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Vuoi inviare di nuovo la mail di conferma?",
"resetPwd":"Reimpostare la password",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":"Le ricariche dei diritti necessitano di disconnettersi e di riconnettersi",
"rules":"RULES",
"scope":"Ambito",
@ -320,6 +321,16 @@
"wait":"Attendere",
"waitingmessage":"Autenticazione in corso, attendere prego",
"warning":"Avvertimento",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Benvenuto sul tuo portale di autenticazione protetta.",
"yesResendMail":"Sì, rinvia e-mail",
"yourAddress":"Know your address",
@ -337,4 +348,4 @@
"yourProfile":"Know your profile",
"yourTotpKey":"La tua chiave TOTP",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetPwd":"Reset my password",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"rules":"RULES",
"scope":"Scope",
@ -320,6 +321,16 @@
"wait":"Wait",
"waitingmessage":"Authentication in progress, please wait",
"warning":"Warning",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Welcome on your secured authentication portal.",
"yesResendMail":"Yes, resend the mail",
"yourAddress":"Know your address",
@ -337,4 +348,4 @@
"yourProfile":"Know your profile",
"yourTotpKey":"Your TOTP key",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Czy chcesz, aby wiadomość z potwierdzeniem została ponownie wysłana?",
"resetPwd":"Zresetuj moje hasło",
"rest2f":"Kod weryfikacyjny",
"retry":"Retry",
"rightsReloadNeedsLogout":"Przeładowania uprawnień wymaga wylogowania i ponownego zalogowania",
"rules":"RULES",
"scope":"Zakres",
@ -320,6 +321,16 @@
"wait":"Czekaj",
"waitingmessage":"Uwierzytelnianie w toku, proszę czekać",
"warning":"Ostrzeżenie",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Witamy w portalu z bezpiecznym uwierzytelnianiem.",
"yesResendMail":"Tak, wyślij ponownie pocztę",
"yourAddress":"Twój adres",
@ -337,4 +348,4 @@
"yourProfile":"Twój profil",
"yourTotpKey":"Twój klucz TOTP",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetPwd":"Reset my password",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"rules":"RULES",
"scope":"Scope",
@ -320,6 +321,16 @@
"wait":"Wait",
"waitingmessage":"Authentication in progress, please wait",
"warning":"Warning",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Welcome on your secured authentication portal.",
"yesResendMail":"Yes, resend the mail",
"yourAddress":"Know your address",
@ -337,4 +348,4 @@
"yourProfile":"Know your profile",
"yourTotpKey":"Your TOTP key",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Você deseja que o e-mail de confirmação seja reenviado?",
"resetPwd":"Redefinir minha senha",
"rest2f":"Código de verificação",
"retry":"Retry",
"rightsReloadNeedsLogout":"Recarregamentos de direitos precisam que saia e faça login novamente",
"rules":"REGRAS",
"scope":"Escopo",
@ -320,6 +321,16 @@
"wait":"Espere",
"waitingmessage":"Autenticação em progresso. Por favor, aguarde",
"warning":"Aviso",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Bem-vindo ao seu portal de autenticação seguro.",
"yesResendMail":"Sim, reenvie o e-mail",
"yourAddress":"Saiba o seu endereço",
@ -337,4 +348,4 @@
"yourProfile":"Saiba o seu perfil",
"yourTotpKey":"Sua chave TOTP",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetPwd":"Reset my password",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"rules":"RULES",
"scope":"Scope",
@ -320,6 +321,16 @@
"wait":"Wait",
"waitingmessage":"Authentication in progress, please wait",
"warning":"Warning",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Welcome on your secured authentication portal.",
"yesResendMail":"Yes, resend the mail",
"yourAddress":"Know your address",
@ -337,4 +348,4 @@
"yourProfile":"Know your profile",
"yourTotpKey":"Your TOTP key",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Onay e-postasının tekrar gönderilmesini ister misiniz?",
"resetPwd":"Parolamı sıfırla",
"rest2f":"Doğrulama kodu",
"retry":"Retry",
"rightsReloadNeedsLogout":"Yetkiler yeniden yüklendiğinde çıkış yapıp tekrar giriş yapmanız gerekir",
"rules":"KURALLAR",
"scope":"Kapsam",
@ -320,6 +321,16 @@
"wait":"Bekleyin",
"waitingmessage":"Kimlik doğrulama işlemi devam ediyor, lütfen bekleyin",
"warning":"Uyarı",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Güvenli kimlik doğrulama portalına hoş geldiniz.",
"yesResendMail":"Evet, tekrar e-posta gönder",
"yourAddress":"Adresini bil",
@ -337,4 +348,4 @@
"yourProfile":"Profilini bil",
"yourTotpKey":"TOTP anahtarınız",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"Bạn có muốn gửi lại thư xác nhận không?",
"resetPwd":"Đặt lại mật khẩu của tôi",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":"Tải lại quyền cần đăng xuất và đăng nhập lại",
"rules":"RULES",
"scope":"Phạm vi",
@ -320,6 +321,16 @@
"wait":"Hãy đợi",
"waitingmessage":"Authentication in progress, please wait",
"warning":"Cảnh báo",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"Chào mừng bạn đến với cổng thông tin xác thực được bảo mật của bạn.",
"yesResendMail":"Có, gửi lại thư",
"yourAddress":"Know your address",
@ -337,4 +348,4 @@
"yourProfile":"Know your profile",
"yourTotpKey":"Your TOTP key",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"您想确认邮件被重新发送吗?",
"resetPwd":"重置我的密码",
"rest2f":"Verification code",
"retry":"Retry",
"rightsReloadNeedsLogout":"重新加载权限需要登出并且再次登录",
"rules":"RULES",
"scope":"Scope",
@ -320,6 +321,16 @@
"wait":"等待",
"waitingmessage":"Authentication in progress, please wait",
"warning":"警告",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"欢迎来到您的加密认证 portal",
"yesResendMail":"好的,重新发送邮件",
"yourAddress":"Know your address",
@ -337,4 +348,4 @@
"yourProfile":"Know your profile",
"yourTotpKey":"Your TOTP key",
"yubikey2f":"Yubikey"
}
}

View File

@ -270,6 +270,7 @@
"resentConfirm":"您是否要重新傳送確認郵件?",
"resetPwd":"重設我的密碼",
"rest2f":"驗證代碼",
"retry":"Retry",
"rightsReloadNeedsLogout":"重新載入權限需要登出然後再次登入",
"rules":"RULES",
"scope":"範圍",
@ -320,6 +321,16 @@
"wait":"等待",
"waitingmessage":"正在進行驗證,請稍候",
"warning":"警告",
"webAuthnBrowserFailed":"Browser failed to obtain WebAuthn credential",
"webAuthnBrowserInProgress":"WebAuthn authentication in progress. Please follow your browser's instructions",
"webAuthnFailed":"WebAuthn authentication failed",
"webAuthnRegisterFailed":"WebAuthn registration failed",
"webAuthnRegisterInProgress":"WebAuthn registration in progress. Please follow your browser's instructions",
"webAuthnRequired":"WebAuthn authentication required",
"webAuthnUnsupported":"Your web browser does not support WebAuthn",
"webauthn2f":"WebAuthn",
"webauthn2fWelcome":"Security device registration",
"webauthnAlreadyRegistered":"This device is already registered",
"welcomeOnPortal":"歡迎使用您的安全驗證首頁。",
"yesResendMail":"是的,重新傳送電子郵件",
"yourAddress":"知道您的地址",
@ -337,4 +348,4 @@
"yourProfile":"知道您的個人檔案",
"yourTotpKey":"您的 TOTP 金鑰",
"yubikey2f":"Yubikey"
}
}

View File

@ -0,0 +1,43 @@
<TMPL_INCLUDE NAME="header.tpl">
<div class="container">
<TMPL_IF NAME="AUTH_ERROR">
<div class="message message-<TMPL_VAR NAME="AUTH_ERROR_TYPE"> alert"><span trmsg="<TMPL_VAR NAME="AUTH_ERROR">"></span></div>
</TMPL_IF>
<TMPL_IF NAME="DATA">
<div id="color" class="message message-positive alert"><span id="msg" trspan="webAuthnRequired"></span></div>
<form id="verify-form" action="/webauthn2fcheck" method="post">
<input type="hidden" id="credential" name="credential" value="" />
<input type="hidden" id="token" name="token" value="<TMPL_VAR NAME="TOKEN">" />
<input type="hidden" id="checkLogins" name="checkLogins" value="<TMPL_VAR NAME="CHECKLOGINS">" />
<input type="hidden" id="stayconnected" name="stayconnected" value="<TMPL_VAR NAME="STAYCONNECTED">" />
<input type="hidden" name="skin" value="<TMPL_VAR NAME="SKIN">" />
</form>
<script type="application/init">
<TMPL_VAR NAME="DATA">
</script>
<!-- //if:jsminified
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">/common/js/webauthn-ui.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">/common/js/webauthncheck.min.js"></script>
//else -->
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">/common/js/webauthn-ui.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">/common/js/webauthncheck.js"></script>
<!-- //endif -->
</TMPL_IF>
</div>
<div class="buttons">
<div class="btn btn-primary" role="button" id="retrybutton">
<span class="fa fa-repeat"></span>
<span trspan="retry">Retry</span>
</div>
<a href="<TMPL_VAR NAME="PORTAL_URL">?cancel=1&skin=<TMPL_VAR NAME="SKIN">" class="btn btn-secondary" role="button">
<span class="fa fa-home"></span>
<span trspan="cancel">Cancel</span>
</a>
</div>
<TMPL_INCLUDE NAME="footer.tpl">

View File

@ -0,0 +1,58 @@
<TMPL_INCLUDE NAME="header.tpl">
<main id="menucontent" class="container">
<div id="color" class="message message-<TMPL_VAR NAME="ALERT"> alert"><span id="msg" trspan="<TMPL_VAR NAME="MSG">"></span></div>
<div class="card">
<div class="card-body">
<div id="u2fPermission" trspan="u2fPermission" class="alert alert-info">You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.</div>
<div class="row">
<div class="col-md-6 text-center">
<img src="<TMPL_VAR NAME="STATIC_PREFIX"><TMPL_VAR NAME="SKIN">/webauthn.png" alt="WebAuthn" title="WebAuthn" />
</div>
<div class="col-md-6">
<div class="form-group">
<label for="keyName"><span trspan="name">Name</span></label>
<input type="text" class="form-control" id="keyName" name="keyName" value="MyFidoKey" trplaceholder="name" />
</div>
</div>
</div>
<div class="buttons">
<span id="verify" class="btn btn-info" role="button">
<span class="fa fa-check-circle"></span>
<span trspan="verify">Verify</span>
</span>
<span id="register" class="btn btn-success" role="button">
<span class="fa fa-floppy-o"></span>
<span trspan="register">Register</span>
</span>
</div>
</div>
</div>
</main>
<div class="buttons">
<a href="<TMPL_VAR NAME="PORTAL_URL">2fregisters?skin=<TMPL_VAR NAME="SKIN">" class="btn btn-info" role="button">
<span class="fa fa-shield"></span>
<span trspan="sfaManager">sfaManager</span>
</a>
<a id="goback" href="<TMPL_VAR NAME="PORTAL_URL">?cancel=1&skin=<TMPL_VAR NAME="SKIN"><TMPL_IF NAME="AUTH_URL">&url=<TMPL_VAR NAME="AUTH_URL"></TMPL_IF>" class="btn btn-primary" role="button">
<span class="fa fa-home"></span>
<span trspan="goToPortal">Go to portal</span>
</a>
</div>
<!-- //if:jsminified
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">/common/js/webauthn-ui.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">/common/js/webauthnregistration.min.js"></script>
//else -->
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">/common/js/webauthn-ui.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">/common/js/webauthnregistration.js"></script>
<!-- //endif -->
<TMPL_INCLUDE NAME="footer.tpl">