Authentication Alpha
parent
d1663cbbbe
commit
f001840670
105
css/ln.vue.css
105
css/ln.vue.css
|
@ -73,6 +73,33 @@ body {
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ln-view {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
section#header {
|
||||
flex-grow: 0;
|
||||
margin-bottom: 1em;
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
section#body {
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
section#footer {
|
||||
flex-grow: 0;
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
.json {
|
||||
white-space: pre;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
|
@ -153,7 +180,6 @@ div.ln-select::after {
|
|||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.ln-navitem {
|
||||
|
@ -211,6 +237,83 @@ div.ln-nav-children > .ln-navitem:first-of-type {
|
|||
border-top: none;
|
||||
}
|
||||
|
||||
div.ln-statusbar {
|
||||
position: relative;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
|
||||
border-top: 1px solid black;
|
||||
|
||||
padding: 8px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
div.ln-statusbar > div {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
|
||||
padding: 4px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
|
||||
border-left: 1px solid #D0D0D0;
|
||||
}
|
||||
div.ln-statusbar > div:first-of-type {
|
||||
text-align: left;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
div.ln-statusbar > div.ln-background-tasks {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.ln-background-tasks {
|
||||
position: relative;
|
||||
}
|
||||
div.ln-background-tasks > div {
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
||||
white-space: pre;
|
||||
|
||||
left: 4px;
|
||||
bottom: 80%;
|
||||
|
||||
overflow-y: visible;
|
||||
overflow-x: hidden;
|
||||
|
||||
background-color: blanchedalmond;
|
||||
border: 1px solid black;
|
||||
|
||||
padding: 4px;
|
||||
padding-right: 32px;
|
||||
padding-left: 16px;
|
||||
|
||||
margin-right: 24px;
|
||||
|
||||
opacity: 0;
|
||||
height: 10px;
|
||||
|
||||
transition: opacity 500ms 50ms, height 0ms 550ms;
|
||||
}
|
||||
div.ln-background-tasks:hover > div {
|
||||
opacity: 1.0;
|
||||
height: 8em;
|
||||
|
||||
transition: opacity 500ms 50ms, height 500ms 50ms;
|
||||
}
|
||||
div.ln-background-tasks > div > div[state="waiting"] {
|
||||
color: silver;
|
||||
}
|
||||
div.ln-background-tasks > div > div[state="failed"] {
|
||||
color: red;
|
||||
}
|
||||
div.ln-background-tasks > div > div[state="ready"] {
|
||||
color: green;
|
||||
}
|
||||
|
||||
div.ln-upload {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
|
61
demo.html
61
demo.html
|
@ -17,19 +17,32 @@
|
|||
table#controls > tbody > tr > td:nth-child(3) {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
div#frame {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="frame">
|
||||
<h1>ln.vue Demo Application</h1>
|
||||
|
||||
<div v-if="false">
|
||||
<h2>Please wait for application to be loaded...</h2>
|
||||
</div>
|
||||
|
||||
<ln-navbar></ln-navbar>
|
||||
<router-view></router-view>
|
||||
<div id="frame" class="ln-view">
|
||||
<section id="header">
|
||||
<h1>ln.vue Demo Application</h1>
|
||||
<ln-navbar></ln-navbar>
|
||||
</section>
|
||||
<section id="body">
|
||||
<div v-if="false">
|
||||
<h2>Please wait for application to be loaded...</h2>
|
||||
</div>
|
||||
|
||||
<div id="viewPane" class="ln-viewpane">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</section>
|
||||
<section id="footer">
|
||||
<ln-statusbar></ln-statusbar>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
@ -72,16 +85,6 @@
|
|||
}
|
||||
};
|
||||
|
||||
/* LNVue.addRouteTemplate(
|
||||
"/state",
|
||||
`<div>Current User Input object:<br><br>
|
||||
<span class="json">{{ JSON.stringify(controls,null,4) }}</span>
|
||||
</div>`
|
||||
);
|
||||
|
||||
LNVue.addRoute("/controls","/controls.html");
|
||||
LNVue.addRoute("/table","/table.html");
|
||||
*/
|
||||
let message = { value: "" };
|
||||
|
||||
app = new LNVue("#frame",{
|
||||
|
@ -197,6 +200,18 @@
|
|||
},
|
||||
});
|
||||
|
||||
app.addModule({
|
||||
navigation: {
|
||||
login: {
|
||||
label: "Login Pane",
|
||||
path: "/login",
|
||||
}
|
||||
},
|
||||
routes: {
|
||||
'/login': `<div>Login Pane<br><ln-login-pane></ln-login-pane></div>`,
|
||||
}
|
||||
});
|
||||
|
||||
app.Start();
|
||||
|
||||
LNVue.onidle(()=>{
|
||||
|
@ -206,6 +221,14 @@
|
|||
},1000);
|
||||
});
|
||||
|
||||
for (let n=5;n<15;n++){
|
||||
LNVue.LNPromise(n + " sec promise test",(resolve,reject)=>{
|
||||
setTimeout(()=>{
|
||||
resolve();
|
||||
},n * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -90,6 +90,36 @@ Vue.directive('tooltip',{
|
|||
},
|
||||
});
|
||||
|
||||
|
||||
Vue.component('ln-statusbar',{
|
||||
computed: {
|
||||
CurrentPromises: function(){
|
||||
return LNVue.$_.getCurrentPromises();
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div
|
||||
class="ln-statusbar"
|
||||
>
|
||||
<div>{{ LNVue.$_.statusText }}</div>
|
||||
<div style="flex-grow: 0;">{{ LNVue.$_.socket && LNVue.$_.socket._state }}</div>
|
||||
<div
|
||||
class="ln-background-tasks"
|
||||
>{{ Object.keys(CurrentPromises).length || "No" }} Background Tasks
|
||||
<div
|
||||
v-if="Object.keys(CurrentPromises).length"
|
||||
>
|
||||
<div
|
||||
v-for="promise in CurrentPromises"
|
||||
:state="promise.state"
|
||||
>{{ promise.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex-grow: 0;">{{ LNVue.$_.Version() }}</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
|
||||
Vue.component('ln-navitem',{
|
||||
props: {
|
||||
value: {
|
||||
|
@ -167,6 +197,18 @@ Vue.component('ln-textfield',{
|
|||
v-bind:value="value"
|
||||
v-on:input="$emit('input', $event.target.value)">`,
|
||||
});
|
||||
Vue.component('ln-password',{
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
template: `<input
|
||||
type="password"
|
||||
v-bind:value="value"
|
||||
v-on:input="$emit('input', $event.target.value)">`,
|
||||
});
|
||||
|
||||
Vue.component('ln-textarea',{
|
||||
props: {
|
||||
|
@ -466,4 +508,97 @@ Vue.component('ln-select',{
|
|||
});
|
||||
|
||||
|
||||
Vue.component('ln-login-pane',{
|
||||
props: {
|
||||
},
|
||||
methods: {
|
||||
stage1: function(){
|
||||
console.log("login stage1", this.identityName);
|
||||
|
||||
LNVue.$_
|
||||
.requestChallenges(this.identityName)
|
||||
.then((challenges)=>{
|
||||
challenges = challenges.message.Challenges;
|
||||
if (challenges.length > 0){
|
||||
LNVue.$_.identity.identityName = this.identityName;
|
||||
LNVue.$_.identity.challenges = challenges;
|
||||
}
|
||||
});
|
||||
},
|
||||
authenticate(challenge){
|
||||
console.log("authenticate()",challenge);
|
||||
},
|
||||
authenticateSeededPassword(challenge){
|
||||
let encoder = new TextEncoder();
|
||||
let seed = LNVue.decodeHex(challenge.AuthenticationParameters);
|
||||
let password = encoder.encode(challenge.prove);
|
||||
|
||||
console.log("password", LNVue.encodeHex(password),password);
|
||||
console.log("seed", LNVue.encodeHex(seed),seed);
|
||||
|
||||
let secretSource = ArrayBuffer.combine(seed, password, seed);
|
||||
|
||||
crypto.subtle.digest("SHA-256",secretSource)
|
||||
.then((secret)=>{
|
||||
let challengebytes = LNVue.decodeB64(challenge.Challenge);
|
||||
secret = new Uint8Array(secret);
|
||||
console.log("secret", LNVue.encodeHex(secret),secret);
|
||||
|
||||
let proveSource = ArrayBuffer.combine(challengebytes, secret, challengebytes);
|
||||
|
||||
crypto.subtle.digest("SHA-256",proveSource)
|
||||
.then((prove)=>{
|
||||
prove = LNVue.encodeB64(new Uint8Array(prove));
|
||||
LNVue.$_.authenticate(this.identityName,challenge.SecureAttributeID,challenge.Challenge,prove);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
data: ()=>{
|
||||
return {
|
||||
identityName: "",
|
||||
};
|
||||
},
|
||||
template: `<div>
|
||||
<div
|
||||
v-if="LNVue.$_.identity.uniqueID">
|
||||
IdentityName: {{ LNVue.$_.identity.uniqueID }} / {{ LNVue.$_.identity.identityName }}
|
||||
</div>
|
||||
<div
|
||||
v-if="!LNVue.$_.identity.uniqueID">
|
||||
<div
|
||||
v-if="LNVue.$_.identity.identityName == ''"
|
||||
><label for="LNIdentityName">Username</label>
|
||||
<ln-textfield
|
||||
name="LNIdentityName"
|
||||
v-model="identityName"></ln-textfield>
|
||||
<button
|
||||
:disabled="identityName == ''"
|
||||
@click="stage1();"
|
||||
>continue</button>
|
||||
</div>
|
||||
<div
|
||||
v-if="LNVue.$_.identity.identityName != ''"
|
||||
>
|
||||
<div
|
||||
v-for="challenge in LNVue.$_.identity.challenges"
|
||||
>
|
||||
<div
|
||||
v-if="challenge.SecureAttributeTypeName == 'SeededPassword'"
|
||||
>{{ challenge.SecureAttributeLabel }}
|
||||
<ln-password
|
||||
v-model="challenge.prove"
|
||||
></ln-password>
|
||||
<button
|
||||
@click="authenticateSeededPassword(challenge)"
|
||||
>login</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`,
|
||||
});
|
||||
|
||||
|
||||
})();
|
396
js/ln.vue.js
396
js/ln.vue.js
|
@ -1,5 +1,280 @@
|
|||
var LNVue = (function (){
|
||||
let _unique = new Date().getTime();
|
||||
function uniqueID(){
|
||||
return _unique++;
|
||||
}
|
||||
|
||||
let currentPromises = {};
|
||||
|
||||
/*\
|
||||
|*|
|
||||
|*| Base64 / binary data / UTF-8 strings utilities (#1)
|
||||
|*|
|
||||
|*| https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
|
||||
|*|
|
||||
|*| Author: madmurphy
|
||||
|*|
|
||||
\*/
|
||||
|
||||
/* Array of bytes to base64 string decoding */
|
||||
|
||||
function b64ToUint6 (nChr) {
|
||||
|
||||
return nChr > 64 && nChr < 91 ?
|
||||
nChr - 65
|
||||
: nChr > 96 && nChr < 123 ?
|
||||
nChr - 71
|
||||
: nChr > 47 && nChr < 58 ?
|
||||
nChr + 4
|
||||
: nChr === 43 ?
|
||||
62
|
||||
: nChr === 47 ?
|
||||
63
|
||||
:
|
||||
0;
|
||||
|
||||
}
|
||||
|
||||
function base64DecToArr (sBase64, nBlockSize) {
|
||||
|
||||
var
|
||||
sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
|
||||
nOutLen = nBlockSize ? Math.ceil((nInLen * 3 + 1 >>> 2) / nBlockSize) * nBlockSize : nInLen * 3 + 1 >>> 2, aBytes = new Uint8Array(nOutLen);
|
||||
|
||||
for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
|
||||
nMod4 = nInIdx & 3;
|
||||
nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4;
|
||||
if (nMod4 === 3 || nInLen - nInIdx === 1) {
|
||||
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
|
||||
aBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
|
||||
}
|
||||
nUint24 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return aBytes;
|
||||
}
|
||||
|
||||
/* Base64 string to array encoding */
|
||||
|
||||
function uint6ToB64 (nUint6) {
|
||||
|
||||
return nUint6 < 26 ?
|
||||
nUint6 + 65
|
||||
: nUint6 < 52 ?
|
||||
nUint6 + 71
|
||||
: nUint6 < 62 ?
|
||||
nUint6 - 4
|
||||
: nUint6 === 62 ?
|
||||
43
|
||||
: nUint6 === 63 ?
|
||||
47
|
||||
:
|
||||
65;
|
||||
|
||||
}
|
||||
|
||||
function base64EncArr (aBytes) {
|
||||
|
||||
var eqLen = (3 - (aBytes.length % 3)) % 3, sB64Enc = "";
|
||||
|
||||
for (var nMod3, nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
|
||||
nMod3 = nIdx % 3;
|
||||
/* Uncomment the following line in order to split the output in lines 76-character long: */
|
||||
/*
|
||||
if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) { sB64Enc += "\r\n"; }
|
||||
*/
|
||||
nUint24 |= aBytes[nIdx] << (16 >>> nMod3 & 24);
|
||||
if (nMod3 === 2 || aBytes.length - nIdx === 1) {
|
||||
sB64Enc += String.fromCharCode(uint6ToB64(nUint24 >>> 18 & 63), uint6ToB64(nUint24 >>> 12 & 63), uint6ToB64(nUint24 >>> 6 & 63), uint6ToB64(nUint24 & 63));
|
||||
nUint24 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return eqLen === 0 ?
|
||||
sB64Enc
|
||||
:
|
||||
sB64Enc.substring(0, sB64Enc.length - eqLen) + (eqLen === 1 ? "=" : "==");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class LNVuePromise
|
||||
{
|
||||
constructor(label,executor){
|
||||
this.promise = new Promise(
|
||||
(resolve,reject) => {
|
||||
executor(
|
||||
(v) => {
|
||||
this._s.state = "ready";
|
||||
resolve(v);
|
||||
this.release();
|
||||
},
|
||||
(e) => {
|
||||
this._s.state = "failed";
|
||||
reject(e);
|
||||
this.release();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
if (!label)
|
||||
label = "N.D.";
|
||||
|
||||
this._s = {
|
||||
label,
|
||||
state: "waiting"
|
||||
};
|
||||
|
||||
this.idx = uniqueID();
|
||||
|
||||
currentPromises[this.idx] = this._s;
|
||||
}
|
||||
|
||||
label(){
|
||||
return this._s.label;
|
||||
}
|
||||
|
||||
state(){
|
||||
return this._s.state;
|
||||
}
|
||||
|
||||
release(){
|
||||
setTimeout(()=>{
|
||||
Vue.delete(currentPromises, this.idx);
|
||||
},1000);
|
||||
}
|
||||
|
||||
then(){
|
||||
return this.promise.then.apply(this.promise, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
class LNVueWebSocket
|
||||
{
|
||||
constructor(lnvue,o){
|
||||
this.LNVue = lnvue;
|
||||
this.options = Object.assign({},o);
|
||||
|
||||
if (!this.options.url)
|
||||
this.options.url = this.constructURL();
|
||||
|
||||
this._id = 1;
|
||||
this.defaultTimeout = 30000;
|
||||
this.websocket = null;
|
||||
this.callbacks = {};
|
||||
|
||||
this._state = "initialized";
|
||||
this._retry = null;
|
||||
|
||||
this.closing = false;
|
||||
}
|
||||
|
||||
constructURL(){
|
||||
var pageURI = window.location;
|
||||
|
||||
var scheme = pageURI.scheme == "https" ? "wss:" : "ws:";
|
||||
var host = pageURI.host;
|
||||
|
||||
return scheme + "//" + host + "/socket";
|
||||
}
|
||||
|
||||
open(){
|
||||
if (this._retry){
|
||||
clearTimeout(this._retry);
|
||||
}
|
||||
this.closing = false;
|
||||
|
||||
this.websocket = new WebSocket(this.options.url);
|
||||
this.websocket.onopen = (e) =>{ console.log("WebSocket connected"); this._state = "ONLINE"; };
|
||||
this.websocket.onclose = (e)=>{ this._onclose(e); this._state = "OFFLINE"; };
|
||||
this.websocket.onerror = (e)=>{ this._onerror(e); this._state = "ERROR"; };
|
||||
this.websocket.onmessage = (e)=>{ this._onmessage(e); };
|
||||
return this;
|
||||
}
|
||||
|
||||
close(){
|
||||
if (this.websocket){
|
||||
this.closing = true;
|
||||
this.websocket.close(200,"close() called");
|
||||
}
|
||||
}
|
||||
|
||||
request(msgtype,msg,timeout){
|
||||
let message = {
|
||||
id: this._id++,
|
||||
type: msgtype,
|
||||
message: msg,
|
||||
}
|
||||
|
||||
if (!timeout)
|
||||
timeout = this.defaultTimeout;
|
||||
|
||||
if (timeout != -1){
|
||||
return new Promise((resolve,reject)=>{
|
||||
let to = setTimeout(()=>{
|
||||
delete this.callbacks[message.id];
|
||||
reject("timed out");
|
||||
},timeout);
|
||||
|
||||
this.callbacks[message.id] = (msgtype,msg)=>{
|
||||
clearTimeout(to);
|
||||
delete this.callbacks[message.id];
|
||||
if (msgtype == "error")
|
||||
reject(msg);
|
||||
else
|
||||
resolve({type: msgtype,message: msg});
|
||||
};
|
||||
|
||||
this.websocket.send(
|
||||
JSON.stringify(message)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
new Promise((resolve,reject)=>{
|
||||
this.websocket.send(
|
||||
JSON.stringify(message)
|
||||
);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
_onclose(evt){
|
||||
this.websocket = null;
|
||||
this.options.onclose && this.options.onclose(evt);
|
||||
if (!this.closing)
|
||||
{
|
||||
this._retry = setTimeout(() => {
|
||||
this._retry = null;
|
||||
console.log("reconnect...")
|
||||
this.open();
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
_onerror(evt){
|
||||
this.options.onerror && this.options.onerror(evt);
|
||||
}
|
||||
_onmessage(evt){
|
||||
try
|
||||
{
|
||||
let j = JSON.parse(evt.data);
|
||||
let cb = this.callbacks[ j.id ];
|
||||
cb && cb(j.type,j.message);
|
||||
} catch(exc){
|
||||
console.log(exc,evt.data);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class LNVue
|
||||
{
|
||||
|
@ -13,17 +288,25 @@
|
|||
this.data = Object.assign({}, options.data, { LNVue: this, msg: "Hello World" });
|
||||
this.promises = [];
|
||||
|
||||
this.globals = {
|
||||
currentPromises,
|
||||
};
|
||||
|
||||
this.statusText = "LNVue preparing";
|
||||
|
||||
Vue.prototype.$LNVue = this;
|
||||
LNVue.$_ = this;
|
||||
|
||||
console.log("LNVue: preparing");
|
||||
|
||||
this.navigation = {};
|
||||
this.identity = {
|
||||
uniqueID: null,
|
||||
identityName: "",
|
||||
};
|
||||
|
||||
Promise
|
||||
.all(LNVue.promises)
|
||||
.then(()=>{
|
||||
console.log("LNVue: starting");
|
||||
this.status("LNVue: starting");
|
||||
|
||||
LNVue.vueRouter.addRoutes([{
|
||||
path: "*",
|
||||
|
@ -31,7 +314,9 @@
|
|||
template: `<h2>404 Not Found</h2>The URL you tried to reach is not existing.`,
|
||||
},
|
||||
}]);
|
||||
|
||||
},
|
||||
(cause)=>{
|
||||
this.status("LNVue: start failed: " + cause);
|
||||
});
|
||||
|
||||
this.vue = null;
|
||||
|
@ -47,11 +332,31 @@
|
|||
data: this.data,
|
||||
router: LNVue.vueRouter,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
LNVue.onidle(()=>{
|
||||
this.socket = new LNVueWebSocket(this);
|
||||
this.socket.open();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Version(){ return "0.2alpha"; };
|
||||
getCurrentPromises() {
|
||||
return this.globals.currentPromises;
|
||||
}
|
||||
|
||||
status(){
|
||||
if (arguments.length == 1){
|
||||
this.statusText = arguments[0];
|
||||
return this;
|
||||
} else if (arguments.length == 0){
|
||||
return this.statusText;
|
||||
} else
|
||||
throw "LNVue.status(): too many arguments";
|
||||
}
|
||||
|
||||
addModule(modSpec){
|
||||
if (modSpec.navigation instanceof Object){
|
||||
|
@ -61,13 +366,16 @@
|
|||
LNVue.$each(modSpec.routes,(key,route)=>{
|
||||
if ((route instanceof Object) && route.url)
|
||||
{
|
||||
let p = new Promise((resolve,reject)=>{
|
||||
let p = LNVue.LNPromise( "addModule()", (resolve,reject)=>{
|
||||
LNVue
|
||||
.fetch(route.url)
|
||||
.then((src)=>{
|
||||
this.addRoute(key,{ template: src, data: ()=>{ return this.data; }, });
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
(cause)=>{
|
||||
console.log("loading route.url failed: ",cause);
|
||||
});
|
||||
});
|
||||
this.promises.push(p);
|
||||
} else if (route instanceof Object){
|
||||
|
@ -85,6 +393,45 @@
|
|||
]);
|
||||
}
|
||||
|
||||
/* Authentication API */
|
||||
|
||||
requestChallenges(identityName,secureAttributeTypeName){
|
||||
return new Promise((resolve,reject)=>{
|
||||
this.socket.request("AuthenticationRequest",{
|
||||
IdentityName: identityName,
|
||||
SecureAttributeTypeName: secureAttributeTypeName,
|
||||
})
|
||||
.then((challenges)=>{
|
||||
console.log("rx challenges",challenges);
|
||||
resolve(challenges);
|
||||
},
|
||||
(error)=>{
|
||||
console.log("Login challenges could not be retrieved", error);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
authenticate(identityName,secureAttributeID,challenge,prove){
|
||||
let authenticationProve = {
|
||||
IdentityName: identityName,
|
||||
SecureAttributeUniqueID: secureAttributeID,
|
||||
Challenge: challenge,
|
||||
Prove: prove,
|
||||
};
|
||||
console.log("authenticate", authenticationProve);
|
||||
this.socket.request("AuthenticationProve", authenticationProve)
|
||||
.then((identity)=>{
|
||||
console.log("auth",identity);
|
||||
},
|
||||
(error)=>{
|
||||
console.log("auth error",error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Object.defineProperty( LNVue, '$LNVue', {
|
||||
|
@ -155,8 +502,7 @@
|
|||
LNVue.promises = [];
|
||||
|
||||
LNVue.fetch = function(url,cb){
|
||||
let self = this;
|
||||
return new Promise(function(resolve,reject){
|
||||
return LNVue.LNPromise("loading",(resolve,reject)=>{
|
||||
fetch(url)
|
||||
.then((response => {
|
||||
if (response.status.toString().startsWith("2"))
|
||||
|
@ -182,5 +528,37 @@
|
|||
});
|
||||
};
|
||||
|
||||
LNVue.LNPromise = function(label, action){
|
||||
console.log(label,action);
|
||||
return new LNVuePromise(label, action);
|
||||
}
|
||||
|
||||
LNVue.encodeB64 = base64EncArr;
|
||||
LNVue.decodeB64 = base64DecToArr;
|
||||
|
||||
LNVue.encodeHex = (bytes) => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
|
||||
LNVue.decodeHex = (hexString) => new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
|
||||
|
||||
ArrayBuffer.combine = function(...args){
|
||||
let byteLength = 0;
|
||||
args.forEach((arg,index)=>{
|
||||
byteLength = byteLength + arg.byteLength;
|
||||
});
|
||||
|
||||
let result = new Uint8Array(byteLength);
|
||||
let p = 0;
|
||||
args.forEach((arg,index)=>{
|
||||
for (let n=0;n<arg.byteLength;n++)
|
||||
{
|
||||
result[p++] = arg[n];
|
||||
}
|
||||
});
|
||||
console.log("combine",new Uint8Array(result));
|
||||
return result.buffer
|
||||
};
|
||||
|
||||
LNVue.prototypes = {};
|
||||
LNVue.prototypes.LNVuePromise = LNVuePromise;
|
||||
|
||||
return LNVue;
|
||||
})();
|
Loading…
Reference in New Issue