UNPKG

libra-auth

Version:

An authentication method using Libra's Public Key and Secret Key.

459 lines (417 loc) 15.7 kB
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <meta name=viewport content="width=device-width, initial-scale=1"> <title>Ticket Center</title> <link rel="stylesheet" href="./css/main.css"> <style> </style> <script src="./js/libraweb-v2.js"></script> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" crossorigin="anonymous"></script> </head> <body> <div id=contents> <section> <img class=logo alt="libra logo" src="./img/libra.png"> </section> <header> <div class=header> <h2>Bob's Ticket Center</h2> The ticket price is <strong>10 Libra</strong>. If Buy Button click sent 10 Libra and you can take the Ticket. </div> </header> <section> <div id=buy-button></div> </section> <section> <div id=balance></div> </section> <footer> <div id=powerd> <nav> powerd by <a href="https://github.com/toshirot/libra-auth">libra-auth</a> </nav> </div> </footer> </div> </body> <script> $(function(){ // Eventually the libraweb code will be Hide from window object later. //============================================================================= // main object // //------------------------------------------------------------------------------ //------------------------------------------------------------ // Object for Ticket Demo with Libra Auth method // // Thanx: libraweb loaded by libraweb-v2.js is browserified // bandifycol/libra-web and perfectmak/libra-core. // Alice's client is connected to proxy ac-libra-testnet.kulap.io in kulapio/libra-core. let Ticket={ libraweb: window.libraweb//Hide from window later ,librawebBuffer: window.librawebBuffer//Hide from window later ,conn: { wss_arry: [] ,wss: null ,wsNonStopFlg:true }//for WebSocket }; //============================================================================= // data // //------------------------------------------------------------------------------ //------------------------------------------------------------ // for LIBRA //In this demo, the address is fixed beforehand. const fromAddrAlice='9291e14f5e7c1ce211ce9477154faddb0c308af2f6a10324f893e2e59a13ff80' const toAddrBob='9291e14f5e7c1ce211ce9477154faddb0c308af2f6a10324f893e2e59a13ff80' //unit of Libra const LIBRA_UNIT=1000000 //The ticket price is 10 Libra const TICKET_AMOUNT=10*LIBRA_UNIT;//10*1000000 is 10 Libra //First mint for Alice const FIRST_MINT_FOR_ALICE=TICKET_AMOUNT*2 //host for mint const DEFAULT_FAUCET_HOST='faucet.testnet.libra.org' //protocol for mint. http or https const DEFAULT_FAUCET_PROTOCOL='http' //------------------------------------------------------------ // for DOM //loading html const LOADING_HTML='<div class="loader">Loading...</div>' //buy button const BUY_BUTTON_HTML= `<form> <button id=btn class="btn-buy ">Buy</button> </form>` //------------------------------------------------------------ // for MESSAGE const M_DO_YOU_BUY_CONFIRM='Do you want to buy a ticket? The Cost is Libra 20.' //------------------------------------------------------------ // for WebSocket const HB=JSON.stringify({type:'hb'})//heartbeat const HEARTBEAT_INTERVAL=10000//60000 //============================================================================= // Dom operations // //------------------------------------------------------------------------------ //------------------------------------------------------------ // onload //make buy button mkHtml('#buy-button', BUY_BUTTON_HTML) // $('#balance').html(LOADING_HTML) // mint 20 Libra to Allice doMint(fromAddrAlice, FIRST_MINT_FOR_ALICE) getBalance(fromAddrAlice, function(balance){ $('#balance').html(mkClientProfeel(fromAddrAlice, balance)) }) //------------------------------------------------------------ // Event for click or tap const clickevt = 'ontouchstart' in window ? 'touchstart' : 'click'; $('.btn-buy').bind(clickevt, function(){ event.preventDefault() // some codes for click or tap $(this).css({background: '#bbb'}) //chk do you buy? let okbuy=checkConfirm(M_DO_YOU_BUY_CONFIRM) if(okbuy){ // buy let res = getPubKey(12345, 0) console.log(res) $('#buy-button').html(LOADING_HTML) setTimeout(function(){ $('#buy-button').html('lets go chk tx') },1000) } else { // Not buy $(this).css({background: '#39298C'}) } }) //============================================================================= // WebSocket Operations // //----------------------------------------------------------------------------- let wss=wssLibraAuth('wss://wss.libra-auth.com:8888/') window.wss=wss// //------------------------------------------------------------ // pre) Connect with WebSocket // @url {String} target wss Server // @return {Object} WebSocket instance function wssLibraAuth(url){ let op={ protocol: 'wss.libra-auth.com' ,uid: 'wss-' + uuidv4() ,hbTimeout:null } let wss = new WebSocket(url, op.protocol) console.log(Ticket.conn, Ticket.conn.wss_arry) Ticket.conn.wss_arry.push(wss) wss.op=op wss.on = function (type, fnc){ this.addEventListener(type, fnc) return this } wss .on('open', function(){heartbeat(wss)}) .on('message', function(msg){onmsg(wss,msg)}) .on('close', function clear() { clearTimeout(this.pingTimeout) console.log('closed wss:',this.op.uid) }) return wss; } //------------------------------------------------------------ // heartbeat function heartbeat(wss) { // Start heartbeat send clearInterval(wss.op.hbTimeout); wss.send(HB); wss.op.hbTimeout = setInterval(() => { if(wss.readyState===WebSocket.OPEN){ wss.send(HB); } else { wssDelAll() } }, HEARTBEAT_INTERVAL); } //------------------------------------------------------------ // pre) onmsg // @wss {Object} WebSocket instance // @msg {String} stringifyd json message function onmsg(wss, msg){ if(!wss)return if(!msg)return if(!msg.data)return let data try{ data = JSON.parse(msg); if(msg.data.type!==undefined){ console.log(1, data) return } else if(msg.data.type==='hb'){ data=msg.data console.log(2, data) } else if(msg.data.type==='sigs'){ data=msg.data console.log(3, data) } else { console.log(4, data) } } catch(e){ return } if(!data.sigs)return alert('received',data.sigs) } window.wssDelAll=wssDelAll function wssDelAll(callback) { let wss_arry=Ticket.conn.wss_arry //del all wss object for(var i=0;i<wss_arry.length;i++){ console.log(i , 'deleted wss' , (wss_arry[i].op.uid||'') ,new Date() ) wss_arry[i].close() } Ticket.conn.wss_arry=[] if(callback)callback() } //============================================================================= // Util Functions // //----------------------------------------------------------------------------- //------------------------------------------------------------ // pre) mk html // @targetElm {String} selector for jquery e.g. '#hoge' // @html {String} html function mkHtml(targetElm, html){ $(targetElm).html(html) } //------------------------------------------------------------ // pre) clientプロフィールのHTMLを作る // @return {String} html function mkClientProfeel(fromAddrAlice, balance){ return ` <div class=youraddr><span>Your Address:</span>${fromAddrAlice}</div> <div class=yourbalance><span>Your Balance:</span>${balance}</div>` } //------------------------------------------------------------ // pre) clientを作る // @return {String} addres hex function createClient(){ let address='' return address } //------------------------------------------------------------ // pre) onload時にここでは事前にmintで入金する // @address {Number} libra address // @amount {Number} libra amount function doMint(address, amount, host, protocol){ if(!chkInput())return if(!host)host=DEFAULT_FAUCET_HOST if(!protocol)protocol=DEFAULT_FAUCET_PROTOCOL let url=`http://${host}?amount=${amount}&address=${address}` fetch(url, { method: 'post', mode: 'no-cors' }).then(data => console.log(data) ).catch(error => console.error(error)) function chkInput(){ //simple check input if(!address){ alert('address is required.') return false } try{amount=+amount}catch(e){ alert('amount must be Number') return false } //if(amount>TICKET_AMOUNT){ alert('amount is over 10 Libra. \n amount:'+amount+'/ '+TICKET_AMOUNT); return false } return true } } //------------------------------------------------------------ // pre) get balance of address // @address {string} target address // @callback{function} callback function getBalance(address, callback){ const client = new Ticket.libraweb.LibraClient({ protocol: 'https', host: 'ac-libra-testnet.kulap.io', port: '443', // dataProtocol: 'grpc-web-text' }) const addr = new Ticket.libraweb.AccountAddress( Uint8Array.from( Ticket.librawebBuffer.from(address, 'hex') ) ) const accountState = client .getAccountState(addr) .then((value) => { if(callback)callback(value.balance) }, (reason) => { console.log('error:',reason) }) } //------------------------------------------------------------ // 1) Buy buttonを押したときに送金の意志を確認する // @msg {String} massage // @retuen {Bool} true|false function checkConfirm(msg){ return window.confirm(msg) } //------------------------------------------------------------ // 2) from address から to addressへ送金する // @from {String} libra from address // @to {String} libra to address // @amount {Number} libra amount function transfer(from, to, amount){ } //------------------------------------------------------------ // 3)4) 最新のシークエンス番号を取得する // @addrees {Number} libra addrees // @return sequence{Number} last sequence number function getSequence(addrees){ let sequence return sequence } //------------------------------------------------------------ // 3)4) トランザクションを取得する // @addrees {Number} libra addrees // @sequence{Number} sequence number // @return {object} transaction function getTx(addrees, sequence){ //get tx from testnet let tx={ public_key: 'test' } return tx } //------------------------------------------------------------ // 3)4) pubKeyを取得する // @addrees {Number} libra addrees // @sequence{Number} sequence number // @return {String} pubKey function getPubKey(addrees, sequence){ let tx = getTx(addrees, sequence) let pubKey=tx.public_key return pubKey } //------------------------------------------------------------ // 5) メッセージのハッシュを取得する // @msg {String} message // @return msg hash{String} msg hash by SHA3 function mkMsgHash(msg){ return (new SHA3(512)).update(msg).digest('hex') } //------------------------------------------------------------ // 5)7) メッセージと秘密鍵絵でシグネチャを生成する // @msg {String} message // @prikey {String} Private key // @return msg hash{String} msg hash by SHA3 function mkMsgHash(msg, prikey){ return prikey.sign(msg).toHex() } //------------------------------------------------------------ // 5) WebSocketでsignatureとmassageを送る // @msg {String} message // @sig {String} signature function sendMsgAndSig(msg, sig){ const oj=JSON.stringify({ msg: msg, sig, sig }) if(window.wss){ window.wss.send(oj) } } //------------------------------------------------------------ // 6)8) メッセージとシグネチャを公開鍵で検証する // @msg {String} message // @sig {String} signature // @pubkey {String} Public key // @return {bool} true|false function mkMsgHash(msg, sig, pubkey){ // return pubkey.verify(msg, sig) } //------------------------------------------------------------ // 7) QRコードを生成する // @sig {String} signature // @return qr {Image} QR png image for of sig function mkMsgHash(sig){ return //qr } // ----------------------------------------------------------------------------- // uuidv4 // function uuidv4() { // Thanx for // https://gist.github.com/jcxplorer/823878 // https://web.archive.org/web/20150201084235/http://blog.snowfinch.net/post/3254029029/uuid-v4-js let uuid = '' let random; for (let i = 0; i < 32; i++) { random = Math.random() * 16 | 0; if (i == 8 || i == 12 || i == 16 || i == 20) { uuid += '-'; } uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16); } setTimeout(function() { uuid=random=null; }, 1000); return uuid; } }) </script> </html>