EExcel 丞燕快速查詢2

EExcel 丞燕快速查詢2
EExcel 丞燕快速查詢2 https://sandk.ffbizs.com/

bip39 mnemonic bip32 seed ed25519 elliptic



const bip39 = require('bip39')
const bip32 = require('bip32');
const EC = require('elliptic').ec;

json =`test json file`
mnemonic = "簡 熙 夢 幾 聲 可 高 汪 煙 版 統 仇"
path = "m/2018'/5'/1'/0/1"

const sJWSinit = async () => {
  console.log('-----sJWS Initial Start----- \n');

  dkey = await DeriveKey(mnemonic, path)
  console.log("\nGet dkey: %o \n", dkey)
  
  console.log('\n-----elliptic ed25519 Start----- \n');

  var EdDSA = require('elliptic').eddsa
  var ec = new EdDSA('ed25519');
  var eckeypair = ec.keyFromSecret(dkey.privateKey)
  
  var privateKeyHex = new Buffer.from(eckeypair.getSecret()).toString('hex')
  var publickeyHex = new Buffer.from(eckeypair.getPublic()).toString('hex')
  console.log("private key hex: %o", privateKeyHex)
  console.log("public key hex: %o\n", publickeyHex)

  var signature = eckeypair.sign(json).toHex();
  console.log("signature: %o\n", signature)

  var ec2 = new EdDSA('ed25519');
  var ec2keypair2 = ec2.keyFromPublic(publickeyHex, 'hex');
  console.log("EdDSA json verify: %o", ec2keypair2.verify(json, signature));
}

(async () => {
  console.log("--- aysnc sJWS init---")
  await sJWSinit();
})();

async function DeriveKey(mnemonic, derivePath) {
  if (bip39.validateMnemonic(mnemonic)) { console.log("mnemonic is fake!") }

  return bip39.mnemonicToSeed(mnemonic).then((vseed)=>{
    var root = bip32.fromSeed(vseed)
    var PathNode = root.derivePath(derivePath)
        
    console.log("# PATH 是 m/2018'/5'/1'/0/1/0  因為底下為derive(0),所以 path + '/0' \n")
    console.log("privateKey (Hex): %o", PathNode.derive(0).privateKey.toString('hex'))
    console.log("publicKey (Hex): %o", PathNode.derive(0).publicKey.toString('hex')) // 024ac10a81e3a0f86cb4dad68c6a26031d805a057f36048f80a5b91b1c2cb0588c 符合

    return {
      prv_buf: PathNode.derive(0).privateKey,
      pub_buf: PathNode.derive(0).publicKey,
      wif: PathNode.derive(0).toWIF(),
      publicKey: PathNode.derive(0).publicKey.toString('hex'),
      privateKey: PathNode.derive(0).privateKey.toString('hex'),
      path: derivePath
    }
  }).catch((e) => {
    console.error('handle error here: ', e.message)
  })
     
}

bitcoinjs-lib HDNode.fromSeedBuffer error bip39 bip32 Address bitcoin ethereum

bitcoinSecp256r1.HDNode.fromSeedBuffer 無法使用,目前正確應該是用 bitcoinSecp256r1.bip32.fromSeed

jsrsasign 有異常


const bip39 = require('bip39')
const bip32 = require('bip32');
const bitcoinSecp256r1 = require('bitcoinjs-lib')
const ethUtil = require('ethereumjs-util')
const EC = require('elliptic').ec;

// bitcoinSecp256r1.HDNode.fromSeedBuffer 無法使用,目前正確應該是用 bitcoinSecp256r1.bip32.fromSeed

mnemonic = "簡 熙 夢 幾 聲 可 高 汪 煙 版 統 仇"
path = "m/2018'/5'/1'/0/1"
type = "secp256r1"

// 驗證網頁 https://iancoleman.io/bip39/#chinese_traditional

if (bip39.validateMnemonic(mnemonic)) { console.log("mnemonic is fake!") }
const seed = bip39.mnemonicToSeed(mnemonic).then((vseed)=>{
  var root = bip32.fromSeed(vseed)
  var PathNode = root.derivePath(path)

  console.log("---------------------------------------------")
  console.log("# PATH 是 m/2018'/5'/1'/0/1/ \n")
  console.log("Bitcoin Address: %o 符合 \n", getAddress(PathNode)) // 1GcgQJN7XgqkZkQcD4dzaZ7bjCFvQ6wxF2 符合 m/2018'/5'/1'/0/1
  console.log("root toWIF: %o", root.toWIF())
  console.log("PathNode toWIF: %o 符合", PathNode.toWIF()) // Kzq7FAYiWjDAcwU44FvcyCsCpJyLCD19n13FyQgLY6oBNajYcAYz 符合 m/2018'/5'/1'/0/1
  console.log("--------------------------------------------- \n")

  // 底下為derive(0),所以正確是 m/2018'/5'/1'/0/1/0 為 path + '/0'
  console.log("---------------------------------------------")
  console.log("# PATH 是 m/2018'/5'/1'/0/1/0  因為底下為derive(0),所以 path + '/0' \n")
  console.log("privateKey (WIF): %o 符合", PathNode.derive(0).toWIF()) // L5ccMER4KyRn6pY6amvrFAHacpEsKrH1eTjDNeWwgXMnqjSCUU6N 符合
  console.log("privateKey (Buffer): %o", PathNode.derive(0).privateKey)
  console.log("privateKey (String): %o", PathNode.derive(0).privateKey.toString())
  console.log("privateKey (Hex): %o", PathNode.derive(0).privateKey.toString('hex'))
  console.log("privatekeyHex: %o \n", PathNode.derive(0).privkeyHex)
  console.log("publicKey (Hex): %o 符合", PathNode.derive(0).publicKey.toString('hex')) //024ac10a81e3a0f86cb4dad68c6a26031d805a057f36048f80a5b91b1c2cb0588c 符合
  console.log("Bitcoin Address: %o 符合", getAddress(PathNode.derive(0))) //1Gp8AuHiYyBixrvLkKtC4VDhxpvK8PmYEr 符合
  console.log("--------------------------------------------- \n")


  console.log('\n-----elliptic Initial Start----- \n');
  
  var ec = new EC('p256');
  let keyPair = ec.keyFromPrivate("83CFCC6EF1864C3303A5F8DEF2540167CB2DFA5DD22BB8D197B396972525FD56")
  let pubKey = keyPair.getPublic();
  console.log("pubKey: %o", pubKey)

  // https://github.com/kjur/jsrsasign/issues/394
  // sha512('aaa') => d6f644b19812e97b5d871658d6d3400ecd4787faeb9b8990c1e7608288664be77257104a58d033bcf1a0e0945ff06468ebe53e2dff36e248424c7273117dac09
  let msgHash = 'd6f644b19812e97b5d871658d6d3400ecd4787faeb9b8990c1e7608288664be7'

  let signatureBase64 = 'MEUCIBEcfv2o3UwqwV72CVuYi7HbjcoiuSQOULY5d+DuGt3UAiEAtoNrdNWvjfdz/vR6nPiD+RveKN5znBtYaIrRDp2K7Ks='
  let signatureHex = Buffer.from(signatureBase64, 'base64').toString('hex');
  let validSig = ec.verify(msgHash, signatureHex, pubKey);
  console.log("Signature valid? %o \n", validSig);

  // use json
  var ec = new EC('secp256k1');
  keyPair = ec.keyFromPrivate(dkey.publicKey)
  pubKey = keyPair.getPublic();
  console.log("pubKey: %o", pubKey)

  var signature = keyPair.sign(json);
  var derSign = signature.toDER();
  //console.log("signature: %o", signature)
  console.log("json verify: %o", keyPair.verify(json, derSign));


  console.log('\n-----elliptic ed25519 Start----- \n');

  var EdDSA = require('elliptic').eddsa
  var ec2 = new EdDSA('ed25519');
  var ec2keypair = ec2.keyFromSecret(dkey.privateKey)
  //console.log("key: %o", key)
  var signature = ec2keypair.sign(json).toHex();
  console.log("signature: %o", signature)

  var privateKeyHex = new Buffer(ec2keypair.getSecret()).toString('hex')
  var publickeyHex = new Buffer(ec2keypair.getPublic()).toString('hex')
  console.log("private key hex: %o", privateKeyHex)
  console.log("public key hex: %o", publickeyHex)

  var ec2keypair2 = ec2.keyFromPublic(publickeyHex, 'hex');
  console.log("EdDSA json verify: %o", ec2keypair2.verify(json, signature));


  bip39.mnemonicToSeed(mnemonic).then((vseed)=>{
    var root = bitcoinSecp256r1.bip32.fromSeed(vseed)
    var PathNode = root.derivePath(path)
    console.log("bitcoinSecp256r1 privateKey (Hex): %o", PathNode.derive(0).privateKey.toString('hex'))
    console.log("bitcoinSecp256r1 publicKey (Hex): %o", PathNode.derive(0).publicKey.toString('hex')) 
    
    const buf = Buffer.allocUnsafe(32);
    new Buffer.from(msgHash).copy(buf, 0, 0, 32)
    //msgbuf32 = new Buffer("01234567890123456789012345678901")
    console.log("msgHash buf 32: %o", buf.toString("hex"))
    var ecPair = bitcoinSecp256r1.ECPair.fromPrivateKey(PathNode.derive(0).privateKey)
    var signstring = ecPair.sign(buf)
    console.log("signstring: %o", signstring.toString("hex"))
    var verifyresult = ecPair.verify(buf, signstring)
    console.log("verify: %o", verifyresult)
  })
})

DeriveKey(mnemonic, path, type).then((v)=>{
  console.log("dkey: %o", v)
});

function getAddress (node, network) {
  return bitcoinSecp256r1.payments.p2pkh({ pubkey: node.publicKey, network }).address
}

function getEthereumAddress(privkeyHex) {
  const hexAddress = ethUtil.privateToAddress(Buffer.from(privkeyHex, 'hex')).toString('hex')
  const checksumAddress = ethUtil.toChecksumAddress(hexAddress)
  return checksumAddress
}

function DeriveKey(mnemonic, derivePath, type) {
  switch (type) {
    case "secp256r1":
      if (bip39.validateMnemonic(mnemonic)) { console.log("mnemonic is fake!") }

      return bip39.mnemonicToSeed(mnemonic).then((vseed)=>{
        var root = bip32.fromSeed(vseed)
        var PathNode = root.derivePath(derivePath)
          
        console.log("# PATH 是 m/2018'/5'/1'/0/1/0  因為底下為derive(0),所以 path + '/0' \n")
        console.log("privateKey (Hex): %o", PathNode.derive(0).privateKey.toString('hex'))
        console.log("publicKey (Hex): %o 符合", PathNode.derive(0).publicKey.toString('hex')) // 024ac10a81e3a0f86cb4dad68c6a26031d805a057f36048f80a5b91b1c2cb0588c 符合

        const buf = Buffer.allocUnsafe(32);
        PathNode.derive(0).privateKey.copy(buf, 0, 0, 32)
        console.log("Ethereum Address: %o 符合", getEthereumAddress(buf.toString('hex')) ) // 0xe020343a09086F53a203c9A0Ea76010049399575 符合
          
        return {
          pub_buf: PathNode.derive(0).publicKey,
          wif: PathNode.derive(0).toWIF(),
          publicKey: PathNode.derive(0).publicKey.toString('hex'),
          privateKey: PathNode.derive(0).privateKey.toString('hex'),
          ethAddress: getEthereumAddress(buf.toString('hex')),
          path: derivePath
        }
      }).catch((e) => {
        console.log('handle error here: ', e.message)
      })
        
      break;

    default:
      throw "type should be secp256k1 or secp256r1";
  }
}

smart contract storage struct 未初始化 直接使用問題

https://github.com/knownsec/Ethereum-Smart-Contracts-Security-CheckList/blob/master/%E4%BB%A5%E5%A4%AA%E5%9D%8A%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%AE%A1%E8%AE%A1CheckList.md#11-%E6%9C%AA%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9A%84%E5%82%A8%E5%AD%98%E6%8C%87%E9%92%88

https://www.chaindd.com/3102377.html

https://blog.b9lab.com/storage-pointers-in-solidity-7dcfaa536089

https://medium.com/loom-network/ethereum-solidity-memory-vs-storage-how-to-initialize-an-array-inside-a-struct-184baf6aa2eb

Use delete or new

web3 deploy smart contract 1.2.1

Use https://remix.ethereum.org Get Contract json and data.


In remix website, Compile finish. See Compliation Details.


1. ABI: click ABI buttion, get data. Use http://jsonviewer.stack.hu/ remove space

2. Compliation Details -> WEB3DEPLOY -> get data


3. cContract.options.from need put correct.


var Web3 = require("web3");
var provider = new Web3.providers.HttpProvider("http://ganache:8545");
var web3 = new Web3(provider);

//abi
var cContract = new web3.eth.Contract([{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}])

//bytecode
cContract.options.data = '0x608060405234801561001057600080fd5b5060bf8061001f6000396000f30060806040526004361060485763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166360fe47b18114604d5780636d4ce63c146064575b600080fd5b348015605857600080fd5b5060626004356088565b005b348015606f57600080fd5b506076608d565b60408051918252519081900360200190f35b600055565b600054905600a165627a7a72305820765480c908e5e28e3233e18bfa422944b42cad5fc08b77d7b22d3ddd7016a1380029'

cContract.options.from = '0xoooxxxoooxxxoooxxxoooxxxoooxxx'
cContract.options.gas = '4700000'

console.log("web3 version: %o", web3.version)
web3.eth.getAccounts().then(o=>{console.log(o)})

cContract.deploy().send()
.on('error', (error) => {
    console.log("error: %o", error)
})
.on('transactionHash', (transactionHash) => {
    console.log("transactionHash: %o", transactionHash)
})
.on('receipt', (receipt) => {
    // receipt will contain deployed contract address
    console.log("receipt: %o", receipt)
    console.log("receipt.contractAddress: %o", receipt.contractAddress) 
})
.on('confirmation', (confirmationNumber, receipt) => {
    console.log("confirmationNumber: %o", confirmationNumber)
    console.log("confirmation receipt: %o", receipt)
})
.then(function(newContractInstance){
    if (typeof newContractInstance.options.address !== 'undefined') {
        console.log('Contract mined! address: ' + newContractInstance.options.address);
    }else{
        console.log("newContractInstance.address is undefined!")
    }
});

HDWalletProvider web3 smart contract connection need to stop or pool

HDWalletProvider engine.stop()



p = HDWalletProvider(MNEMONIC_SYSTEM, "http://ganache:8545", 0);
p.engine.stop();


HDWalletProvider engine.stop() and pool



export function GetHdProvider(id: number, rpcurl: string) {
  //return new HDWalletProvider(MNEMONIC_SYSTEM, url, id);

  return id==0?Provider1Pool.acquire():Provider2Pool.acquire();
}

// Normal use
const hdProvider0 = await GetHdProvider(0, providerUrl).then(function(client) {return client}).catch(function(err) {throw new HttpException(err.toString(), HttpStatus.BAD_REQUEST);});

const hdProvider1 = await GetHdProvider(1, providerUrl).then(function(client) {return client}).catch(function(err) {throw new HttpException(err.toString(), HttpStatus.BAD_REQUEST);});

// Normal release
ReleaseHDProvider1(hdProvider1 );

// Pool code
const genericPool = require("generic-pool");

const opts = {
  max: 10, // maximum size of the pool
  min: 2, // minimum size of the pool
  idleTimeoutMillis: 30000,
  log: true
};

const factory0 = {  // maybe different parms
  create: function() {
    return new HDWalletProvider(MNEMONIC_SYSTEM, RPCURL, 0);
  },
  destroy: function(client) {
    client.engine.stop();
  }
};

const factory1 = {  // maybe different parms
  create: function() {
    return new HDWalletProvider(MNEMONIC_SYSTEM, RPCURL, 1);
  },
  destroy: function(client) {
    client.engine.stop();
  }
};

export function ReleaseHDProvider1(client){
  Provider1Pool.release(client);
  console.log("Provider1Pool status: pool.size %o pool.available %o pool.pending %o", Provider1Pool.size, Provider1Pool.available, Provider1Pool.pending)
}

export function ReleaseHDProvider2(client){
  Provider2Pool.release(client);
  console.log("Provider2Pool status: pool.size %o pool.available %o pool.pending %o", Provider2Pool.size, Provider2Pool.available, Provider2Pool.pending)
}

const Provider1Pool = genericPool.createPool(factory0, opts);
const Provider2Pool = genericPool.createPool(factory1, opts);

Project專案

‎Triton Ho‎ https://www.facebook.com/groups/616369245163622/permalink/1736421439825058/

今天不寫發大財的事,直接寫一下project planning的雜感好了。

——————————————————————————————————————————————————————

最兇險的專案不是那些deadline定得很趕的專案,而是那些沒有deadline的專案!

別以為「沒有deadline」是真的沒有deadline耶。

你想一下,跟你大大聲說「錢不是問題的人」,最終有120%是「反正我又沒錢,錢當然不是問題啊~」。

公司不是做慈善的,也不是給工程師來試新玩具的。所有的專案,最終還是要談C/P值。

(再次一句:工程就是來談C/P的,不談C/P請去當藝術家)

所謂「沒有deadline」,這很可能代表……

A) 你的主管現在忙別的專案管理,暫時沒空管這專案。

(然後等他有空回來看這專案時,就會問為何拖這麼久還結不了案了)

B) 你沒法拒絕其他人的需求改動。(背景聲:反正沒deadline,改一下需求去做得更好吧)

C) 你沒法有效限制專案的複雜性,大量的over-engineering。(背景聲:反正沒deadline,寫得好一點/多留一點空間,這樣子未來才容易維護嘛)

A+B+C的後果是……老闆過了三個月,突然有空來看看大家做什麼時,發現這專案已經過了二個月還沒有做完。

然後要求:都做了三個月了,現在再給你二星期時間來結案耶!

結果是:

要麼結不了案,投入大量心力的專案成為上不了市場的垃圾。

要麼是勉強能結案,但是有大量的over-engineering和一堆因為需求改了又改下不好的程式加構。

——————————————————————————————————————————————————————

雖然一堆入市未深的工程師整天會罵專案deadline為何定得那麼硬,一天都不能改……

但是嘛,先不談專案,我們談一下去旅行好了。

去旅行嘛,第一件事當然是跟公司申請休假,然後把信用卡丟給另一半叫她幫忙規劃(註:這是高度危險動作,好孩子絕對別學)。

http://xn--axxxx-fg1h292av9ap80aa49or2n76lzmxyz1bcr7i.com/,sxxxxxxxxx.com,txxxxxxxxxx.com上天天比價比優惠看旅行遊記的生活~

然後如果沒定下死線?應該我進棺材那一天還是在計劃行程中~

(謎之聲:某人站在你身後,她看起來很火……)

計劃行程的死線能不能改?當然不行,公司休假可是改不動啊!!!

回到公司專案,為何公司死線定得那麼硬,很多時候都是跟業務宣傳/合約罰款有關的。

你想像一下,一個手游專案要上市,當然不是先等程式完成後才慢慢宣傳衝人氣的。

一個遊戲要上市,當然是先定好上市日期,然後預先數月就要慢慢地製造話題,找人來做宣傳,一步一步炒熱氣氛。

然後人氣炒到最高點,玩家的期待度到達最大時,遊戲同步開賣大賺特賺那一波。

如果突然發現有bug,遊戲要延期一個月?

sorry囉,遊戲消費是不理性的,過了那一波熱潮,本來會付錢的玩家們早就付給另一個遊戲了。

讓話題多炒熱一個月去等bug先修好?

你以為是炒青菜,你想炒多久就多久嗎?

先不談熱度能否額外維持一個月還不消散。但是,高人流的宣傳管道,網上KOL,不是你想付錢就能立即買到的!

如果你沒法如期把遊戲上市,那麼你這個遊戲很可能就賠本賠很很大囉。

——————————————————————————————————————————————————————

專案deadline不能改,商業社會就是這樣子了。

追求要完美的,你應該去當藝術家不是當工程師的。

怎去在deadline前做完專案,固然跟你是否有留下足夠的buffering有關。

但是,這跟你的專案怎計劃也有很大關係的。

上古時期,有一堆人(CMMI)覺得,只要把文件寫得好,每一個專案把工序所用的時間都記錄下來。

然後你就能越來越變得成熟,能很精準地預估下一個專案所需時間了~

然後這些CMMI人大約會覺得:把台北的象山步道走100次,就能很精準地預估爬玉山攻項要多少時間了(笑~)

(香港版本:走城門水塘100次,就能預估蚺蛇尖攻項要多少時間了)

會行山的人都知道:

地圖/網上文章只能給你一個很基本的大概,一個路線最終要用多少時間/體力,你只能親自走一次才能答出來。

然後嘛……

很多表面上看起來相同的軟體專案,真正做下去時才發現是全新的未知領域……

——————————————————————————————————————————————————————

如果專案deadline不能改,那麼能改的就是:軟件的質素了。

以去旅行為例:

如果你有非常充份的時間,你買機票時大可以找不同銀行的信用卡優惠,看看飛行里數計劃,看看連同旅行一起訂的優惠……

如果沒時間,http://xn--skyxxxxxxx-rl5q.com/,輸入出發和回程時間,那一家最便宜就按下去算了。

一個能賣錢的軟體專案,正常應該可以再拆分為多個sub-task和milestone的。

重點:

首先開始做的,應該是最困難/你最沒法預估開發難度的工作。

A) 

專案越早階段要改動上市日期,你能成功改動宣傳計劃的可能性就越高。

B) 

越早發現專案進度不理想。之後比較容易的sub-task,你還是能以減少testcase coverage,刪掉不重要功能這些手段去追回進度。

如果你把困難而且必要的工作放在最後才做,那麼任何的預估錯誤就是專案延期囉~

(註1:一堆人覺得堅持一定要先寫testcase才能寫程式的……要麼他真的很幸福沒遇上過要衝死線的專案,要麼他活在童話世界……)

(註2:deadline前做不完的軟體功能嘛……如果不是關鍵性的,看看能不能當成bug再後補囉~)

——————————————————————————————————————————————————————

專案到底先做什麼:

我們以(重要/不重要),和(容易/困難)來給每一個sub-task排一下:

如果你明知deadline是完全不合理,你怎也沒可能把全部重要功能都做完,那麼就先做(重要+容易),在死線前能多做一個功能就多一個功能。

否則,先做(重要+困難)的。因為(重要+容易)的工作,常常是總有一點時間可以偷下來的。越近deadline,你越會珍惜你每一秒不做多餘的事。

重要工作全做完後,然後是(不重要+容易),在deadline前能做多少就多少。

(不重要+困難)工作嘛,讓他留在backlog算了。

——————————————————————————————————————————————————————

後記:

在只發了一篇文下,RDBMS課程普通票全賣光了

(謎之聲:你不是說五分鐘會搶光嗎?)

歡迎來買石虎愛心票耶XD

https://datasci.kktix.cc/events/rdbms20191005

另外,高流量雜感的淺談,定在10/10和10/11的早上9:30—12:00(二天內容相同)

請繼續耐心等候正式報名頁面……

HEX 0x string to []byte to string DecodeString

https://play.golang.org/p/i90_qsN2Sz-


package main

import (
 "fmt"
 "encoding/hex"
)

func main() {
 id := "0x1dd84569ad60faa1b6838526ba7156388cf7c8d376ed0ccda9bce0419c2c3519"
 fmt.Printf("Ori ID: %v \n\n", id)
 fmt.Printf("Ori ID[2:]: %v \n\n", id[2:])
 
 byteid := []byte(id)
 fmt.Printf("===== Byte id ===== Decimal \n")
 fmt.Printf("Byte ID: %v \n", byteid)
 fmt.Printf("Byte ID 0x%x \n\n", byteid)
 
 fmt.Printf("===== Decode(Byte id[2:]) ===== Decimal HEX \n")
 byteid = []byte(id[2:])
 fmt.Printf("Byte ID: %v \n", byteid)
 fmt.Printf("Byte ID 0x%x \n\n", byteid)
 n, _ := hex.Decode(byteid, byteid)
 fmt.Printf("Byte ID[2:]: %v \n", byteid)
 fmt.Printf("Byte ID[2:] 0x%x \n", byteid)
 fmt.Printf("Byte ID[2:] [:n]: %v \n", byteid[:n])
 fmt.Printf("Byte ID[2:] [:n] 0x%x \n\n", byteid[:n])

 fmt.Printf("===== id ===== Decimal \n")
 idbyte32 := covertStringTByte32(id)
 fmt.Printf("Byte32 ID: %v \n", idbyte32 )
 //fmt.Printf("String ID: %s \n", idbyte32 )
 fmt.Printf("HEX ID: 0x%x \n\n", idbyte32 )
 
 fmt.Printf("===== id[2:] ===== Decimal \n")
 idbyte32 = covertStringT2Byte32(id)
 fmt.Printf("Byte32 ID: %v \n", idbyte32 )
 //fmt.Printf("String ID: %s \n", idbyte32 )
 fmt.Printf("HEX ID: 0x%x \n\n", idbyte32 )
 
 fmt.Printf("===== DecodeString(id[2:]) ===== HEX \n")
 idbyte32 = covertStringDecodeStringByte32(id)
 fmt.Printf("Byte32 ID: %v \n", idbyte32 )
 //fmt.Printf("String ID: %s \n", idbyte32 )
 fmt.Printf("HEX ID: 0x%x \n", idbyte32 )
}

func covertStringTByte32(t string) [32]byte {
 var b32 [32]byte
 copy(b32[:], t)
 return b32
}

func covertStringT2Byte32(t string) [32]byte {
 var b32 [32]byte
 copy(b32[:], t[2:]) //remove 0x
 return b32
}

func covertStringDecodeStringByte32(t string) [32]byte {
 data, err := hex.DecodeString(t[2:])
 if err != nil {
  fmt.Printf("ERR \n")
 }
 
 fmt.Printf("DecodeString data: %v \n", data)
 fmt.Printf("DecodeString data length: %v \n\n", len(data))
 
 var b32 [32]byte
 copy(b32[:], data)
 return b32
}


Ori ID: 0x1dd84569ad60faa1b6838526ba7156388cf7c8d376ed0ccda9bce0419c2c3519 

Ori ID[2:]: 1dd84569ad60faa1b6838526ba7156388cf7c8d376ed0ccda9bce0419c2c3519 

===== Byte id ===== Decimal 
Byte ID: [48 120 49 100 100 56 52 53 54 57 97 100 54 48 102 97 97 49 98 54 56 51 56 53 50 54 98 97 55 49 53 54 51 56 56 99 102 55 99 56 100 51 55 54 101 100 48 99 99 100 97 57 98 99 101 48 52 49 57 99 50 99 51 53 49 57] 
Byte ID 0x307831646438343536396164363066616131623638333835323662613731353633383863663763386433373665643063636461396263653034313963326333353139 

===== Decode(Byte id[2:]) ===== Decimal HEX 
Byte ID: [49 100 100 56 52 53 54 57 97 100 54 48 102 97 97 49 98 54 56 51 56 53 50 54 98 97 55 49 53 54 51 56 56 99 102 55 99 56 100 51 55 54 101 100 48 99 99 100 97 57 98 99 101 48 52 49 57 99 50 99 51 53 49 57] 
Byte ID 0x31646438343536396164363066616131623638333835323662613731353633383863663763386433373665643063636461396263653034313963326333353139 

Byte ID[2:]: [29 216 69 105 173 96 250 161 182 131 133 38 186 113 86 56 140 247 200 211 118 237 12 205 169 188 224 65 156 44 53 25 56 99 102 55 99 56 100 51 55 54 101 100 48 99 99 100 97 57 98 99 101 48 52 49 57 99 50 99 51 53 49 57] 
Byte ID[2:] 0x1dd84569ad60faa1b6838526ba7156388cf7c8d376ed0ccda9bce0419c2c35193863663763386433373665643063636461396263653034313963326333353139 
Byte ID[2:] [:n]: [29 216 69 105 173 96 250 161 182 131 133 38 186 113 86 56 140 247 200 211 118 237 12 205 169 188 224 65 156 44 53 25] 
Byte ID[2:] [:n] 0x1dd84569ad60faa1b6838526ba7156388cf7c8d376ed0ccda9bce0419c2c3519 

===== id ===== Decimal 
Byte32 ID: [48 120 49 100 100 56 52 53 54 57 97 100 54 48 102 97 97 49 98 54 56 51 56 53 50 54 98 97 55 49 53 54] 
HEX ID: 0x3078316464383435363961643630666161316236383338353236626137313536 

===== id[2:] ===== Decimal 
Byte32 ID: [49 100 100 56 52 53 54 57 97 100 54 48 102 97 97 49 98 54 56 51 56 53 50 54 98 97 55 49 53 54 51 56] 
HEX ID: 0x3164643834353639616436306661613162363833383532366261373135363338 

===== DecodeString(id[2:]) ===== HEX 
DecodeString data: [29 216 69 105 173 96 250 161 182 131 133 38 186 113 86 56 140 247 200 211 118 237 12 205 169 188 224 65 156 44 53 25] 
DecodeString data length: 32 

Byte32 ID: [29 216 69 105 173 96 250 161 182 131 133 38 186 113 86 56 140 247 200 211 118 237 12 205 169 188 224 65 156 44 53 25] 
HEX ID: 0x1dd84569ad60faa1b6838526ba7156388cf7c8d376ed0ccda9bce0419c2c3519 

Program exited.


https://onlineutf8tools.com/convert-hexadecimal-to-utf8

[轉]Go-JWT-RESTful身份认证教程

https://segmentfault.com/a/1190000020329813


1.什么是JWT
JWT(JSON Web Token)是一个非常轻巧的规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息,
一个JWT由三部分组成,Header头部、Claims载荷、Signature签名,

JWT原理类似我们加盖公章或手写签名的的过程,合同上写了很多条款,不是随便一张纸随便写啥都可以的,必须要一些证明,比如签名,比如盖章,JWT就是通过附加签名,保证传输过来的信息是真的,而不是伪造的,

它将用户信息加密到token里,服务器不保存任何用户信息,服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证,


2.JWT构成
一个JWT由三部分组成,Header头部、Claims载荷、Signature签名,

Header头部:头部,表明类型和加密算法
Claims载荷:声明,即载荷(承载的内容)
Signature签名:签名,这一部分是将header和claims进行base64转码后,并用header中声明的加密算法加盐(secret)后构成,即:

let tmpstr = base64(header)+base64(claims)
let signature = encrypt(tmpstr,secret)

//最后三者用"."连接,即:
let token = base64(header)+"."+base64(claims)+"."+signature

oauth2 NewClient InsecureSkipVerify

https://github.com/terraform-providers/terraform-provider-github/blob/master/github/config.go


 ctx := context.Background()

 insecureClient := &http.Client{
  Transport: &http.Transport{
   TLSClientConfig: &tls.Config{
    InsecureSkipVerify: true,
   },
  },
 }
 ctx = context.WithValue(ctx, oauth2.HTTPClient, insecureClient)

 client := oauth2.NewClient(ctx, oauth2.StaticTokenSource(&oauth2.Token{
  AccessToken: c.Param("accesstoken"),
  TokenType:   "Bearer",
 }))

 resp, err := client.Get("https://ory-hydra-login-consent:9020/openid/userinfo")
 if err != nil {
  return newHTTPError(400, "InvalidToken", err.Error())
 }
 defer resp.Body.Close()

 body, err := ioutil.ReadAll(resp.Body)
 if err != nil {
  return newHTTPError(400, "InvalidToken", err.Error())
 }
 c.Logger().Debugf("resp: %s", body)

 var t map[string]interface{}
 err = json.Unmarshal(body, &t)
 if err != nil {
  return newHTTPError(400, "InvalidToken", err.Error())
 }



 return c.JSON(http.StatusOK, t)

Google code view

https://medium.com/@ryanyang1221/%E8%AE%93-google-%E6%95%99%E4%BD%A0-code-review-be251d4d81b4

golang go-ethereum contract string to [32]byte



func covertStringByte32(t string) [32]byte {
 var b32 [32]byte
 copy(b32[:], []byte(t))
 return b32
}

func covertStringByte64(t string) [64]byte {
 var b64 [64]byte
 copy(b64[:], []byte(t))
 return b64
}

golang test e2e

httpexpect star 1159
https://github.com/gavv/httpexpect
https://github.com/gavv/httpexpect/blob/master/_examples/echo_test.go


goconvey
https://segmentfault.com/a/1190000014924022
https://github.com/smartystreets/goconvey/

baloo star 652
https://github.com/h2non/baloo

frisby star 249
https://github.com/verdverm/frisby

apitest star 121
https://github.com/steinfletcher/apitest

[轉]通过 Channel 实现 Goroutine Pool

https://segmentfault.com/a/1190000020185565

[轉]Go学习之Channel总结

https://segmentfault.com/a/1190000020086749

go mod custome model

https://stackoverflow.com/questions/52079662/go-get-cannot-find-local-packages-when-using-multiple-modules-in-a-repo

api/contracts/contract.go


package contracts

import (
 "math/big"
 "strings"
)....

func DeployContract(...)


api/contract.go


package main

import (
 "api/contracts"
...)

func deployContract(c echo.Context) error {
         address, tx, token, err := contracts.DeployContract(auth, client)
...
}

! Best Import is api/go.mod


module api

require (
         api/contracts v0.0.0
...)

replace (
         api/contracts v0.0.0 => ./contracts
...)


And api/contracts/go.mod



module api/contracts

require (
...)

solc abigen docker

sol file put in ~/contracts/sol


File list

~/contracts/sol/Contracts.sol

RUN


docker run -v ~/contracts:/sources ethereum/solc:0.4.23 -o /sources --abi --bin /sources/sol/Contract.sol

File list

~/contracts/sol/Contracts.sol
~/contracts/Contracts.abi
~/contracts/Contracts.bin

1. 0.4.23 check your contract version. This example is pragma solidity ^0.4.23;
2. sol name need be changeed. This example is Contract.sol
3. Permission denied just use root

RUN


docker run -v ~/contracts:/sources ethereum/client-go:alltools-v1.9.2 abigen --abi /sources/Contract.abi --pkg contracts --type Contract --out /sources/Contract.go  --bin /sources/Contract.bin

File list

~/contracts/sol/Contracts.sol
~/contracts/Contracts.abi
~/contracts/Contracts.bin
~/contracts/Contracts.go

1. Contract.abi Contract.go must change by solc output
2. pkg is go source code:package contracts
3. type is go source code:type Cert struct { }
4. bin is go source code:be add "var ContractBin = ..." and "func DeployContract(..."


Error:


docker run -v ~/contracts/sol:/sources ethereum/client-go:alltools-v1.9.2 abigen --sol /sources/Cert.sol --pkg contracts --out /sources/Cert.go

Fatal: Failed to build Solidity contract: exec: "solc": executable file not found in $PATH


Source:
https://solidity.readthedocs.io/en/develop/installing-solidity.html#docker
https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts#generating-the-bindings
https://hub.docker.com/r/ethereum/client-go

https://github.com/ethereum/go-ethereum/blob/master/cmd/abigen/main.go

go-eth

https://medium.com/taipei-ethereum-meetup/%E4%BD%BF%E7%94%A8-go-%E8%88%87%E4%BB%A5%E5%A4%AA%E5%9D%8A%E5%8D%80%E5%A1%8A%E9%8F%88%E4%BA%92%E5%8B%95-%E4%B8%89-7b7b1f40c06a

https://github.com/sc0Vu/go-eth

golang echo rest demo

https://github.com/hyacinthus/restdemo/blob/master/GOLANG-RESTFUL-API.pdf

https://github.com/hyacinthus/restdemo

ethereum explorer etherchain light

https://github.com/gobitfly/etherchain-light

[轉]Web3.js vs Ethers.js

https://github.com/adrianmcli/web3-vs-ethers

Cordova plugin Cache problem

https://stackoverflow.com/questions/26481507/how-to-force-cordova-to-recompile-added-plugins

Cordova plugin會cache
https://stackoverflow.com/questions/26481507/how-to-force-cordova-to-recompile-added-plugins

1、先remove
2、再加回

為了以上動作執行確實,不要直接去改plugin內容,採用下例方式:

1、建立 keep_plugs
2、將plugin放到裡面,然後再add到專案
3、修改後,重新執行remove、add

cordova plugin remove cordova-android-toast
cordova plugin add keep_plugs/cordova-android-toast

Run ubuntu docker like VM

https://jimmylab.wordpress.com/2018/12/05/ssh-docker-container/

CMD ["/usr/sbin/sshd", "-D"]



https://hub.docker.com/r/rastasheep/ubuntu-sshd/

flutter dart json decode encode

Very Important!


{"107年工作":{"zhangqi":[{"name":"王大明1"},{"name":"孫小明1"}],"chaojiangeren":[{"name":"nnn1","addr":"aaa1"},{"name":"nnn2","addr":"aaa2"}]},"108年法會":{"zhangqi":[{"name":"王大明1"},{"name":"孫小明1"}]}}


zhangqi : [ .... ]
chaojiangeren: [ .... ]


zhangqi : [ {....}, {....} ]
chaojiangeren: [ {....}, {....} ]


Can't have \' or \"

If have this, json.decode can't List


List<dynamic> => List<ItemName>
List<dynamic> => List<ItemNameAddr>


List<ItemName> zhangqi = List<ItemName>();
zhangqi.add(new ItemName(name:"王大明1"));
zhangqi.add(new ItemName(name:"孫小明1"));

List<ItemNameAddr> chaojiangeren = List<ItemNameAddr>();
chaojiangeren.add(new ItemNameAddr(name:"nnn1", addr:"aaa1"));
chaojiangeren.add(new ItemNameAddr(name:"nnn2", addr:"aaa2"));


class ItemName {
  String name;

  ItemName({ this.name }) ;
  ItemName.fromJson(Map<String, dynamic> json) : name = json['name'];
  Map toJson() => {"name": name };  //給json.encode使用,沒有的話,會錯誤
}

class ItemNameAddr {
  String name;
  String addr;

  ItemNameAddr({ this.name, this.addr }) ;
  ItemNameAddr.fromJson(Map<String, dynamic> json) : name = json['name'], addr = json['addr'];
  Map toJson() => {"name": name, "addr": addr};  //給json.encode使用,沒有的話,會錯誤
}

Future<List<ItemName>> getListItemName(List maps) async {
  return new List<ItemName>.generate(maps.length, (i) {
    return ItemName(
      name: maps[i]['name'],
    );
  });
}

Future<List<ItemNameAddr>> getListItemNameAddr(List maps) async {
  return new List<ItemNameAddr>.generate(maps.length, (i) {
    return ItemNameAddr(
      name: maps[i]['name'],
      addr: maps[i]['addr'],
    );
  });
}

ethereum sign verify ECDSA part 3 Final ethereumjs-util Elliptic secp256k1

https://medium.com/@antonassocareer/web3-secp256k1-%E7%B0%BD%E7%AB%A0%E8%88%87solidity%E9%A9%97%E7%AB%A0-26ded518cfdc

phone vs secp256k1 vs ethereumjs-util


那代表 phone 產生的是符合ethereum的格式

但因為 signed的長度不符合標準的 secp256k1 ,所以只能用ethereumjs-util的工具,從fromRpcSig 匯入處理,取得 s r v ,後就能進行處理了!


Elliptic 和 secp256k1 各別需要不同的方式,請閱code


const secp256k1 = require('secp256k1')
const ejsu = require('ethereumjs-util')

Web3 = require("web3")
var web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546');

// phone
// private key 
// address 0xAD44A8ea9A9Bb5eF66F041BB921A687331729eB4
// Message Signature Has 0xa05ac71b16172777f683edbc48e9709cffd713a82630232d7c98e0f0df5201d60329658dba83b53fed49307e03d9663c0d2e4476c8b7925c2ed02cc7f881f5271b
// Message Hello
// public key 034e17dc4aef81e0ce6d16686be5e194274795375fc5525f1cdc46fe0b4643d5d6

console.log("\n----- phone -----\n")

var buf_Signed = Buffer.from(web3.utils.hexToBytes("0xa05ac71b16172777f683edbc48e9709cffd713a82630232d7c98e0f0df5201d60329658dba83b53fed49307e03d9663c0d2e4476c8b7925c2ed02cc7f881f5271b"))
var buf_pubkey = Buffer.from(web3.utils.hexToBytes("0x034e17dc4aef81e0ce6d16686be5e194274795375fc5525f1cdc46fe0b4643d5d6"))

console.log("\x1b[32m Public Key: \x1b[0m %s \nlength: %s \n", web3.utils.bytesToHex(buf_pubkey), buf_pubkey.length)
console.log("\x1b[32m singature: \x1b[0m %o \nlength: %s \n", buf_Signed, buf_Signed.length) 

// ethereumjs-util import signature  fromRpcSig
console.log("\n===== ethereumjs-util =====\n")

var fromSigned = ejsu.fromRpcSig(buf_Signed)
console.log("\x1b[32m fromSigned: %o \n", fromSigned) 

var message = "Hello"
prefix = '\x19Ethereum Signed Message:\n' + message.length.toString()
console.log("\x1b[32m prefix: \x1b[0m %s \n", prefix)

var message2 = prefix + message
var buf_msgHash2 = ejsu.keccak256(message2); // this is ok

var buf_msgHash = Buffer.from(web3.utils.hexToBytes(web3.utils.soliditySha3(prefix, message)))
var ecrecover_public_key = ejsu.ecrecover(buf_msgHash, fromSigned.v, fromSigned.r, fromSigned.s)
console.log("\x1b[32m ecrecover_public_key: \x1b[0m %s \n", web3.utils.bytesToHex(ecrecover_public_key))

var address = ejsu.pubToAddress(ecrecover_public_key)
console.log("\x1b[32m address: \x1b[0m %s \n", web3.utils.bytesToHex(address))
console.log("\x1b[32m toChecksumAddress address: \x1b[0m %s \n", ejsu.toChecksumAddress(web3.utils.bytesToHex(address)))
console.log("\x1b[32m address is same address: \x1b[0m %s \n", ejsu.toChecksumAddress(web3.utils.bytesToHex(address)) == '0xAD44A8ea9A9Bb5eF66F041BB921A687331729eB4')


// Elliptic 
console.log("\n===== Elliptic-util =====\n")
var EC = require('elliptic').ec;
var ec = new EC('secp256k1');
//var key = ec.genKeyPair();
var key = ec.keyFromPublic(buf_pubkey); // No Private Key

//r s https://github.com/ethereumjs/ethereumjs-util/blob/599ba5b1c7043a7e155e6032c50d7a01fc63aaf1/src/signature.ts#L70
var r = buf_Signed.slice(0, 32);
var s = buf_Signed.slice(32, 64);
console.log("\x1b[32m Elliptic verify: \x1b[0m %s \n", key.verify(buf_msgHash, {r: r, s: s}));


//secp256k1
console.log("\n===== secp256k1 =====\n")
var DER_signature = secp256k1.signatureExport(buf_Signed.slice(0, 64))
var signature = secp256k1.signatureImport(DER_signature)
console.log("\x1b[32m phone Signed -> DER Signed -> signatureImport: \x1b[0m %s \nlength: %s \n", web3.utils.bytesToHex(signature), signature.length)
console.log("\x1b[32m secp256k1 verify: \x1b[0m %s \n", secp256k1.verify(buf_msgHash, signature, buf_pubkey));

console.log("\n----- phone End -----\n")


// secp256k1
// private key random => 0x9fc00a13bf199dc5606da92d61438c680eeddec04f7a1833405c1466a81c9bd7

console.log("\n----- secp256k1 -----\n")

var buf_PrivateKey = Buffer.from(web3.utils.hexToBytes('0x9fc00a13bf199dc5606da92d61438c680eeddec04f7a1833405c1466a81c9bd7'))
var buf_PublicKey = secp256k1.publicKeyCreate(buf_PrivateKey)
console.log("\x1b[32m Public Key: \x1b[0m %s \nlength: %s \n", web3.utils.bytesToHex(buf_PublicKey), buf_PublicKey.length)

var buf_msg = Buffer.alloc(32, "Hello")
var singature = secp256k1.sign(buf_msg, buf_PrivateKey)
console.log("\x1b[32m singature: \x1b[0m %o \nlength: %s \n", singature, singature.signature.length) 
console.log("\x1b[32m singature: \x1b[0m %s \n", web3.utils.bytesToHex(singature.signature))

var recover_public_key = secp256k1.recover(buf_msg, singature.signature, singature.recovery)
console.log("\x1b[32m Get Back Pubkey: \x1b[0m %s \n", web3.utils.bytesToHex(recover_public_key))
console.log("\x1b[32m recover_public_key is same PublicKey: \x1b[0m %s", web3.utils.bytesToHex(recover_public_key) == web3.utils.bytesToHex(buf_PublicKey))

console.log("\n----- secp256k1 End -----\n")


// ganache
// private key 0x75b25b96be4313c5a102bd4daa6bbeb71414f23e0ae15c0f93fa6d17866003da
// addresss 0xf8d3A2033ebfc7778CD59f676235a8E431b6eeD7

console.log("\n----- ganache -----\n")

// ganache part is OK
var buf_PrivateKey = Buffer.from(web3.utils.hexToBytes('0x75b25b96be4313c5a102bd4daa6bbeb71414f23e0ae15c0f93fa6d17866003da'))
var buf_PublicKey = ejsu.privateToPublic(buf_PrivateKey)
var buf_Address = ejsu.privateToAddress(buf_PrivateKey)
console.log("\x1b[32m Public Key: \x1b[0m %s \nlength: %s \n", web3.utils.bytesToHex(buf_PublicKey), buf_PublicKey.length)
console.log("\x1b[32m Address: \x1b[0m %s \nlength: %s \n", web3.utils.bytesToHex(buf_Address), buf_Address.length)

var message = "Hello"
var buf_msgHash = ejsu.keccak256(message);
var singature = ejsu.ecsign(buf_msgHash, buf_PrivateKey)
console.log("\x1b[32m singature: \x1b[0m %o \n", singature)  // have r s v

var ecrecover_public_key = ejsu.ecrecover(buf_msgHash, singature.v, singature.r, singature.s)
console.log("\x1b[32m ecrecover_public_key: \x1b[0m %s \n", web3.utils.bytesToHex(ecrecover_public_key))
console.log("\x1b[32m ecrecover_public_key is same PublicKey: \x1b[0m %s", web3.utils.bytesToHex(ecrecover_public_key) == web3.utils.bytesToHex(buf_PublicKey))

console.log("\n----- ganache End -----\n")

Result



----- phone -----

 Public Key:  0x034e17dc4aef81e0ce6d16686be5e194274795375fc5525f1cdc46fe0b4643d5d6
length: 33

 singature:  <Buffer a0 5a c7 1b 16 17 27 77 f6 83 ed bc 48 e9 70 9c ff d7 13 a8 26 30 23 2d 7c 98 e0 f0 df 52 01 d6 03 29 65 8d ba 83 b5 3f ed 49 30 7e 03 d9 66 3c 0d 2e ... >
length: 65


===== ethereumjs-util =====

 fromSigned: { v: 27,
  r:
   <Buffer a0 5a c7 1b 16 17 27 77 f6 83 ed bc 48 e9 70 9c ff d7 13 a8 26 30 23 2d 7c 98 e0 f0 df 52 01 d6>,
  s:
   <Buffer 03 29 65 8d ba 83 b5 3f ed 49 30 7e 03 d9 66 3c 0d 2e 44 76 c8 b7 92 5c 2e d0 2c c7 f8 81 f5 27> }

 prefix:   Ethereum Signed Message:
5

 ecrecover_public_key:  0x4e17dc4aef81e0ce6d16686be5e194274795375fc5525f1cdc46fe0b4643d5d66dcc58b79553ea878b6b514b8bd2552090d0fc810bd6f9b4d585f4709f43ed41

 address:  0xad44a8ea9a9bb5ef66f041bb921a687331729eb4

 toChecksumAddress address:  0xAD44A8ea9A9Bb5eF66F041BB921A687331729eB4

 address is same address:  true


===== Elliptic-util =====

 Elliptic verify:  true


===== secp256k1 =====

 phone Signed -> DER Signed -> signatureImport:  0xa05ac71b16172777f683edbc48e9709cffd713a82630232d7c98e0f0df5201d60329658dba83b53fed49307e03d9663c0d2e4476c8b7925c2ed02cc7f881f527
length: 64

 secp256k1 verify:  true


----- phone End -----


----- secp256k1 -----

 Public Key:  0x037ff17f569a94f4b91317a36b54dc9a77cdd6ce004a00821ca0ebc12acaa5188d
length: 33

 singature:  { signature:
   <Buffer 79 a4 11 c0 85 bd 1a 2d 7b bd a5 eb 1e 19 d6 75 f1 40 07 27 f7 83 82 9f 1d f6 2a d2 86 3c 8a eb 62 04 03 78 64 96 f9 10 27 61 d0 ea 79 2b 40 65 d5 45 ... >,
  recovery: 1 }
length: 64

 singature:  0x79a411c085bd1a2d7bbda5eb1e19d675f1400727f783829f1df62ad2863c8aeb620403786496f9102761d0ea792b4065d545608d7905af427ffa2b181b103e28

 Get Back Pubkey:  0x037ff17f569a94f4b91317a36b54dc9a77cdd6ce004a00821ca0ebc12acaa5188d

 recover_public_key is same PublicKey:  true

----- secp256k1 End -----


----- ganache -----

 Public Key:  0xba5ca43c6d8c8ec41a0449ddc35dfee96afd0a112c4667b9d09925913799be627d1a779b6114c8541650c3b31bf88d360b1e3ebc973267003c7452fef6f2da2e
length: 64

 Address:  0xf8d3a2033ebfc7778cd59f676235a8e431b6eed7
length: 20

 singature:  { r:
   <Buffer b7 f7 ff 3c 78 8f 10 db e5 46 d4 10 2a 17 cd 99 1f d3 2c 5a c8 86 e9 31 83 bc 53 8d 5f 92 8f 81>,
  s:
   <Buffer 6d c1 0d 0e 71 42 73 f5 64 64 96 af d4 e1 3d 49 18 09 5f 42 27 e0 0b ae 1f 5a 59 ec af 39 fd e2>,
  v: 27 }

 ecrecover_public_key:  0xba5ca43c6d8c8ec41a0449ddc35dfee96afd0a112c4667b9d09925913799be627d1a779b6114c8541650c3b31bf88d360b1e3ebc973267003c7452fef6f2da2e

 ecrecover_public_key is same PublicKey:  true

----- ganache End -----

ethereum sign verify ECDSA part 2

Sure ethereum signature is 65, but secp256k1 is 64

RangeError: signature length is invalid



Web3 = require("web3")
var web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546');

const secp256k1 = require('secp256k1')
// or require('secp256k1/elliptic')
//   if you want to use pure js implementation in node


//ethereum test  https://github.com/ethereum/go-ethereum/blob/461291882edce0ac4a28f64c4e8725b7f57cbeae/crypto/signature_test.go
msg = web3.utils.hexToBytes("0xd301ce462d3e639518f482c7f03821fec1e602018630ce621e1e7851c12343a6")
signature = web3.utils.hexToBytes("0x638a54215d80a6713c8d523a6adc4e6e73652d859103a36b700851cb0e61b66b8ebfc1a610c57d732ec6e0a8f06a9a7a28df5051ece514702ff9cdff0b11f454")
pubkey = web3.utils.hexToBytes("0x03ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138")
console.log(secp256k1.verify(msg, signature, pubKey))

ethereum sign verify ECDSA part 1

呼叫web3的部份,都需要使用ethereum geth,這部份有點麻煩

Call web3 must use ethereum, this mean need to run ganache or geth. No ok.


jsrsasign is offline to compute

ECDSA 相關的是 https://kjur.github.io/jsrsasign/sample/sample-ecdsa.html

=====
https://medium.com/@angellopozo/ethereum-signing-and-validating-13a2d7cb0ee3
https://dzone.com/articles/signing-and-verifying-ethereum-signatures

public address 只是 verify後拿來驗證是否相同

另一句話 verify後會產生public address,主要是拿sign後的值產生 r s v ,然後再用 合約的功能 ecrecover 處理


public address only for after verify product check

Other way to explain is

After verify get public address. Take signatures to make r s v, then use r s v with contract ecrecover(). ecrecover() run finish get public address.

=====

Use npm secp256k1. When you run code


Web3 = require("web3")
var web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546');

const { randomBytes } = require('crypto')
const secp256k1 = require('secp256k1')
// or require('secp256k1/elliptic')
//   if you want to use pure js implementation in node

// generate message to sign
const msg = Buffer.alloc(32, "Hello") //randomBytes(32)

// generate privKey
let privKey
do {
  privKey = randomBytes(32)
} while (!secp256k1.privateKeyVerify(privKey))

var buf_privatekey = Buffer.from(web3.utils.hexToBytes('0x75b25b96be4313c5a102bd4daa6bbeb71414f23e0ae15c0f93fa6d17866003da'))
console.log("privatekey: %s", web3.utils.bytesToHex(buf_privatekey))

// get the public key in a compressed format
const pubKey = secp256k1.publicKeyCreate(privKey)
console.log("pubKey: %s", web3.utils.bytesToHex(pubKey))

// sign the message
const sigObj = secp256k1.sign(msg, privKey)

//Message Signature Hash 長度
console.log(Buffer.from(web3.utils.hexToBytes("0xa05ac71b16172777f683edbc48e9709cffd713a82630232d7c98e0f0df5201d60329658dba83b53fed49307e03d9663c0d2e4476c8b7925c2ed02cc7f881f5271b")).length)

//public key
pubkey = Buffer.from(web3.utils.hexToBytes("0x034e17dc4aef81e0ce6d16686be5e194274795375fc5525f1cdc46fe0b4643d5d6"))

//標準signature 是64
console.log(sigObj.signature.length)
console.log("secp256k1 sign finish hex: ", web3.utils.bytesToHex(sigObj.signature))

signature = Buffer.from(web3.utils.hexToBytes("0xa05ac71b16172777f683edbc48e9709cffd713a82630232d7c98e0f0df5201d60329658dba83b53fed49307e03d9663c0d2e4476c8b7925c2ed02cc7f881f5271b"))
console.log(web3.utils.bytesToHex(signature))
console.log(secp256k1.verify(msg, signature, pubKey))

// verify the signature
//console.log(secp256k1.verify(msg, sigObj.signature, pubKey))
// => true


https://etherscan.io/verifySig

Address
0xAD44A8ea9A9Bb5eF66F041BB921A687331729eB4

Message Signature Hash
0xa05ac71b16172777f683edbc48e9709cffd713a82630232d7c98e0f0df5201d60329658dba83b53fed49307e03d9663c0d2e4476c8b7925c2ed02cc7f881f5271b

Enter the original message that was signed
Hello

verify ok

Go back see code.
Message Signature Hash 長度 is 65
sigObj.signature.length is 64

So https://github.com/ethereum/go-ethereum/blob/dbb03fe9893dd19f6b1de1ee3b768317f22fd135/crypto/secp256k1/secp256.go#L159

This is Why. And

https://github.com/ethereum/go-ethereum/blob/dbb03fe9893dd19f6b1de1ee3b768317f22fd135/crypto/secp256k1/secp256.go#L114

node 8 nodejs ssl handshake error




const https = require('https');

export async function GetUserinfo(Token) {
    console.log(process.env["NODE_TLS_REJECT_UNAUTHORIZED"])
    process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
    console.log(process.env["NODE_TLS_REJECT_UNAUTHORIZED"])  

    const baseURL = 'https://openid.hydra:9001';
    const userinfoURL = '/userinfo';

    axios({
        method: 'get',
        headers: {
          'Authorization': 'Bearer ' + Token,
          'accept': 'application/json'
        },
        httpsAgent: new https.Agent({
            rejectUnauthorized: false,
            ecdhCurve: 'auto'
        }),
        url: userinfoURL,
        baseURL: baseURL,
        responseType: 'json'
    }).then(function (response) {


process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;

No Need, No mean

Error: self signed certificate



Answer: rejectUnauthorized: false,

HTTPs requests to API fail: 'sslv3 alert handshake failure



Answer: ecdhCurve: 'auto'

Ory Hydra Authorization Code Exchange => access token Use openid-client

https://github.com/panva/node-openid-client/tree/v2.x

Important! WARNING: Node.js 12 or higher is required for openid-client@3 and above. For older Node.js versions use openid-client@2.


So watch https://github.com/panva/node-openid-client/tree/v2.x

node.js package use "openid-client": "2.5.0",

client.authorizationCallback have bug, nonce mismatch always have this error even see https://github.com/panva/node-openid-client/issues/150


Correct way


https://github.com/panva/node-openid-client/blob/f1b4282ac50f7e15fc195f66bf76409af4ec4b6b/lib/client.js

see if (params.code) { Can know use grant

https://github.com/panva/node-openid-client/tree/v2.x#custom-token-endpoint-grants



      const hydraconfig= {
        "oidurl": "https://openid.hydra:9001",
        "redirectUri": "https://t.tt:9010/callback",
        "clientid": "auth-code-client",
        "clientsecretid": "secret"
      }

      //openid-client================
      const { Issuer } = require('openid-client')
      
      const hydraIssuer = await Issuer.discover(hydraconfig.oidurl) // => Promise
      .then(function (hydradiscoverIssuer) {
        console.log('Discovered issuer %s %O', hydradiscoverIssuer.issuer, hydradiscoverIssuer.metadata);
        return hydradiscoverIssuer
      });

      const client = new hydraIssuer.Client({
        client_id: hydraconfig.clientid,
        client_secret: hydraconfig.clientsecretid
      });
      
      var tokenset = await client.grant({
        grant_type: 'authorization_code',
        code: code,
        redirect_uri: hydraconfig.redirectUri,
        code_verifier: '', //No value, because real use in Hydra login-consent. Not use client.authorizationUrl or client.authorizationPost
      });
      console.log(tokenset)

javascript console.log object

console.log('show value string, object %s %O', var.string, var.object);

Ory Hydra Authorization Code Exchange => access token

Before posts about Hydra get access token is use golang HydraOauthConfig.Exchange(ctx, code). This is easy way. But on front website like vue or other framework how to get access token.

Use REST Client to test



POST https://openid.hydra:9001/oauth2/token
Authorization: Basic YXV0aC1jb2RlLWNsaWVudDpzZWNyZXQ=
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=cuNw76aEuckIJJyVssk2LJvqdLXffT-8Kx1s0tYFt6Y.v0Dxc2_yT9ga8c2moKx0fDbwRFVgwryAt5BJM7lOJlM
#&redirect_uri=https://certfront/oid/test/callback
#&scope=openid,offline
#&client_id=auth-code-client
#&code_verifier=
#&state=gczxkznmjkrksgytsemvwgkf

Import is: Authorization: Basic


https://github.com/ory/hydra/issues/631

Not Authorization: Bearer


base64(urlencode(client_id):urlencode(client_secret))


YXV0aC1jb2RlLWNsaWVudDpzZWNyZXQ= => auth-code-client:secret


code is callback code. When you login-consent finish step then callback to your set callback URL. Watch URL inside have code=


example: https://t.tt:9010/callback?code=cuNw76aEuckIJJyVssk2LJvqdLXffT-8Kx1s0tYFt6Y.v0Dxc2_yT9ga8c2moKx0fDbwRFVgwryAt5BJM7lOJlM&scope=openid%20offline&state=gczxkznmjkrksgytsemvwgkf

If code have error message, you need check before any step have incorrect.


In Ory Hydra get access token is not like sdk document


https://www.ory.sh/docs/hydra/sdk/api#the-oauth-20-token-endpoint

You need to sure grant_type=authorization_code Not other options.

But SDK Document No any options example. Only suggestion you use lib. So you need to try many.

like follow
https://www.oauth.com/oauth2-servers/pkce/authorization-code-exchange/
https://community.ory.sh/t/how-configure-grant-implicit-flow/411/14
https://auth0.com/docs/api-auth/tutorials/authorization-code-grant-pkce
https://github.com/oauthjs/express-oauth-server/issues/55
https://www.jianshu.com/p/5cf2b7a45b75
http://www.passportjs.org/docs/oauth/

Then try out a ways.

OK. Mark is not important Required.


#&redirect_uri=https://certfront/oid/test/callback
#&scope=openid,offline
#&client_id=auth-code-client
#&code_verifier=
#&state=gczxkznmjkrksgytsemvwgkf

oauth2 nodejs

https://peach.ebu.io/technical/tutorials/tuto-oauth2-client/

https://www.pveller.com/oauth2-with-passport-10-steps-recipe/

http://www.hitotec.com/authentification-oauth-avec-passportjs-pour-une-api-rest/


https://www.shangyang.me/2018/03/11/javascript-nodejs-passport-04-deepinto-oauth2-authenticate-process/

https://blog.yorkxin.org/2013/09/30/oauth2-4-1-auth-code-grant-flow.html

[轉]如何使用 OpenSSL 建立開發測試用途的自簽憑證 (Self-Signed Certificate)

https://blog.miniasp.com/post/2019/02/25/Creating-Self-signed-Certificate-using-OpenSSL



目前這個方式比較靠普


建立 ssl.conf 設定檔


[req]
prompt = no
default_md = sha256
default_bits = 2048
distinguished_name = dn
x509_extensions = v3_req

[dn]
C = TW
ST = Taiwan
L = Taipei
O = Duotify Inc.
OU = IT Department
emailAddress = admin@example.com
CN = localhost

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = *.localhost
DNS.2 = localhost
DNS.3 = 192.168.2.100


openssl req -x509 -new -nodes -sha256 -utf8 -days 3650 -newkey rsa:2048 -keyout server.key -out server.crt -config ssl.conf

oauth2 nodejs vue

https://www.ory.sh/docs/hydra/integration#interacting-with-oauth-20

https://github.com/lelylan/simple-oauth2

https://www.jianshu.com/p/5cf2b7a45b75

windows iso

http://windowsiso.net/

vue 3 image assets

Vue template Code


src/ooxx/ooxx/xx.vue

assets


File location:assets/img/tt.png

OK

Code:
img src='@/assets/img/tt.png'

Become:
img src="/img/tt.f3b936ef.png"


Failed

Code:
img src='@/img/nchcbclab.png'

img src='assets/img/tt.png'
img src='./assets/img/tt.png'
img src='../assets/img/tt.png'

img src="require('assets/img/tt.png') "
img src="require('./assets/img/tt.png') "
img src="require('../assets/img/tt.png') "



public


File location:public/img/tt.png

OK

Code:
img src= '/img/nchcbclab.png'

Become:
img src= '/img/nchcbclab.png'


Failed

Code:
img src= 'img/nchcbclab.png'

img src= 'public/img/nchcbclab.png'
img src='/public/img/nchcbclab.png'

vue 3 index.html

old vue index.html just copy to public directory.

If public don't have index.hmtl, be craeted by run "npm run serve". But public don't have index.html.
Only "npm run build" create index.html in dist driectory.

More easy understand way:


You delete all project index.html. This time still can run "npm run serve". Watch Website source code <title>Vue App</title>

Then put your custome into public directory then <title>Custome App ooxxooxx </title>

vue babel 7

https://github.com/storybookjs/storybook/issues/5298
https://github.com/webpack/webpack/issues/4039
https://github.com/gmfe/Think/issues/67

Cannot assign to read only property 'exports' of object '#<Object>'


babel.config.js



 'sourceType': 'unambiguous', // 自动推断编译的模块类型(cjs,es6)
 'ignore': [/@babel[/\\]runtime/], // 忽略 @babel/runtime

Full code

module.exports = {
  'sourceType': 'unambiguous', // 自动推断编译的模块类型(cjs,es6)
  'ignore': [/@babel[/\\]runtime/], // 忽略 @babel/runtime
  presets: [
    '@vue/app'
  ]
}

vue 3 vue-cli-service serve vue.config.js package.json docker

"serve": "vue-cli-service serve",

Some page modify vue-cli-service serve --host 0.0.0.0 --port 8978

This may in docker failed.

Error: listen EADDRNOTAVAIL: address not available


So some page modify vue.config.js

Use public is Failed!!

    devServer: {
        public: '0.0.0.0:80', 
        disableHostCheck: true,
    }


Use host port is Correct!!

module.exports = {
    chainWebpack: config => {
        config.module.rules.delete('eslint');
    },
    devServer: {
        host: '0.0.0.0',
        port: '80',
        //public: '0.0.0.0:80',  //無效
        disableHostCheck: true,
    }
}


PS:
.Put eslint is maybe get some eslint error, not about host ip port.
.disableHostCheck can remove for try by yourself env.

Mirror Your Traffic Duplicate

goreplay
https://github.com/buger/goreplay

tcpcopy
https://github.com/session-replay-tools/tcpcopy

teeproxy
https://github.com/chrislusf/teeproxy

duplicator
https://github.com/agnoster/duplicator

goduplicator
https://github.com/mkevac/goduplicator

nginx mirror

haproxy mirror

[轉]How to Mirror Your Traffic with Nginx

https://www.serverlab.ca/tutorials/linux/web-servers-linux/how-to-mirror-your-traffic-with-nginx/

Mirror Your Traffic

ngnix mirror

ipfs

https://www.fil.club/view/77.html

端口8080是HTTP网关,它允许您使用浏览器查询ipfs数据(请参阅此示例)
端口4001是IPFS用于与其他节点通信的群集端口,端口5001用于本地API。
我们5001只会绑定127.0.0.1因为它不应该暴露给外界。


我们已经安装了数据和分段卷。

该data卷用于存储IPFS本地存储(配置和数据库),并且
staging是一个可用于暂存文件以供命令行使用的目录(例如ipfs add)。

如果您只使用API,则可以省略暂存目录卷。当然,随意将这些目录放在除了之外的其他地方/tmp。

[轉]用Go来做以太坊开发

https://github.com/miguelmota/ethereum-development-with-go-book

https://goethereumbook.org/zh/

ethereum explorer

https://github.com/gobitfly/etherchain-light
https://github.com/gobitfly/erc20-explorer

https://github.com/carsenk/explorer


https://github.com/Capgemini-AIE/ethereum-docker/tree/master/monitored-geth-client
https://github.com/cubedro/eth-net-intelligence-api
https://github.com/cubedro/eth-netstats

Browse blocks and transactions
It's nice to have some simple analogue of Etherscan for your local chain browsing. It will be useful to examine transactions, balances, blocks and etc. It appeared that it is quite difficult to find an open-source good solution for geth. After several tries I found an acceptable solution called ETHExplorer V2. Clone it into explorer-v2 folder. To Dockerize it I had to make 2 changes. First create a Dockerfile


# ./explorer-v2/Dockerfile
FROM node:6
 
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN npm install && \
    node_modules/.bin/bower install --allow-root

And change start script in package.json to "start": "http-server ./app -a 0.0.0.0 -p 8000 -c-1". This is required to allow connections to explorer from any IP (outside docker). Next we should create a service for explorer


 ./docker-compose.yml
# ...
explorer:
    build: explorer-v2
    container_name: explorer
    command: npm start
    ports:
        - "8000:8000"

nestjs csrf

https://gitissue.com/repos/jiayisheji/blog

pass csrf https://github.com/expressjs/csurf/issues/21

main.ts



import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path'
import { AppModule } from './app.module';
import * as cookieSession from 'cookie-session';
import * as helmet from 'helmet';
import * as cookieParser from 'cookie-parser';
import * as csurf from 'csurf';
import * as rateLimit from 'express-rate-limit';

async function bootstrap() {
  const app = await NestFactory.create(
    AppModule,
  );

  app.init()
  
  app.useStaticAssets(join(__dirname, '..', 'public'));
  app.setBaseViewsDir(join(__dirname, '..', 'views'));
  app.setViewEngine('pug');

  app.set('trust proxy', 1);

  app.use(cookieSession({
    name: 'session',
    keys: ['key1', 'key2']
  }));

  //app.enableCors();
  app.use(helmet());
  app.use(cookieParser());
  //app.use(csurf({ cookie: true }));  //正常是這行,但有些API POST時需要略過csrf
  app.use(function (req, res, next) {
    var mw = csurf({ cookie: true });
    // console.log(req.url)  // check real get url
    if (req.url === '/testpostcsrf') return next();  //pass csrf check
    mw(req, res, next);
  });
  app.use(
    rateLimit({
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 100, // limit each IP to 100 requests per windowMs
    }),
  );

  await app.listen(3000);
}
bootstrap();


layout.pug



doctype html
html
  head
    title= title
    meta(content= csrfToken, name='csrf-token')
  body
    block content

login.pug



extends layout

block content
    h1 Please log in
    if error
        p.
            #{error}
    form(action="/login",method="POST")
        input(type="hidden",name="_csrf",value=csrfToken)
        input(type="hidden",name="challenge",value=challenge)
        table(style="")
            tr
                td
                    input(type="email",id="email",name="email",placeholder="email@foobar.com")
                td.
                    (Example: "foo@bar.com")
            tr
                td
                    input(type="password",id="password",name="password")
                td.
                    (Example: "foobar")
        input(type="checkbox",id="remember",name="remember",value="1")
        label(for="remember") Remember me
        br
        input(type="submit",id="accept",value="Log in")




nest.js 让我们用Nestjs来重写一个CNode

https://gitissue.com/repos/jiayisheji/blog

這網站中的 让我们用Nestjs来重写一个CNode(上、中、下) 幫了大忙,減少大量的浪費時間

===========
html -> jade/pug
http://html2jade.aaron-powell.com/

when you html meta want to become jade/pug

layout.pug

meta(content= csrfToken, name='csrf-token')

nodejs expressjs

https://expressjs.com/en/advanced/best-practice-security.html

OpenID hydra docker-compose hydra-login-consent-node mariadb


docker-compose


version: '3.3'

services:
  ory-hydra-postgres:
    image: postgres:9.6
    #restart: always
    environment:
      - POSTGRES_USER=hydra
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=hydra
    volumes:
      - hydradata:/var/lib/postgresql/data:rw
    networks:
      - openid
  # 第一次執行postgres要做資料庫格式建立 PS: network依佈屬環境為主 docker network ls 確認
  # docker run -it --rm \
  #   --network openid \
  #   oryd/hydra:latest \
  #   migrate sql --yes postgres://hydra:secret@ory-hydra-postgres:5432/hydra?sslmode=disable
  
  ory-hydra:
    image: oryd/hydra:latest
    restart: unless-stopped
    ports:
      - "9001:4444"
      - "9002:4445"
    environment:
      - SECRETS_SYSTEM=this_needs_to_be_the_same_a
      - DSN=postgres://hydra:secret@ory-hydra-postgres:5432/hydra?sslmode=disable
      - URLS_SELF_ISSUER=https://openid.hydra:9001/
      - URLS_CONSENT=http://192.168.99.100:9020/consent
      - URLS_LOGIN=http://192.168.99.100:9020/login
      - LOG_LEVEL=debug
      - OAUTH2_EXPOSE_INTERNAL_ERRORS=true
      - SERVE_PUBLIC_CORS_ENABLED=true
      - SERVE_PUBLIC_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE
      - SERVE_ADMIN_CORS_ENABLED=true
      - SERVE_ADMIN_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE
      - SERVE_TLS_KEY_BASE64=LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJZz09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUlHa0FnRUJCRENLbkdnVnFJVzdZaW5iUWV5UEd5UTQ0R3U2VVFEelU5SENLYjMzTWlmeFJYRTBkbnU2KzdadQowdEJUcUhQRHVMeWdCd1lGSzRFRUFDS2haQU5pQUFSbng1Nk9jeGNyRWRsYmU4TXRSdUVxWGV2OEREcmh6ZWJGCjM4NlI4Q2RQWDRlUWI2Zll6ekFUL3V3STBsTDdvRmlEWEM3Q0JLWmZUcTdFSzN4TzNXWlpSSjJrMEQ3TnNLd2cKVEpZenJxT0JpczBNeGtva2FUWVVyemhKMXBKY3lmWT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
      - SERVE_TLS_CERT_BASE64=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNQVENDQWNLZ0F3SUJBZ0lKQU13RjRiVDRvSnh0TUFvR0NDcUdTTTQ5QkFNQ01Gd3hDekFKQmdOVkJBWVQKQWtGVk1STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbgphWFJ6SUZCMGVTQk1kR1F4RlRBVEJnTlZCQU1NREc5d1pXNXBaQzVvZVdSeVlUQWVGdzB4T1RBMk1UY3dNVEl4Ck16ZGFGdzB5T1RBMk1UUXdNVEl4TXpkYU1Gd3hDekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJREFwVGIyMWwKTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXhGVEFUQmdOVgpCQU1NREc5d1pXNXBaQzVvZVdSeVlUQjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkdmSG5vNXpGeXNSCjJWdDd3eTFHNFNwZDYvd01PdUhONXNYZnpwSHdKMDlmaDVCdnA5alBNQlArN0FqU1V2dWdXSU5jTHNJRXBsOU8KcnNRcmZFN2RabGxFbmFUUVBzMndyQ0JNbGpPdW80R0t6UXpHU2lScE5oU3ZPRW5Xa2x6SjlxTlFNRTR3SFFZRApWUjBPQkJZRUZHK3Z6ZkIxYmVnM1VadEpYRXZWOWRNa1hvNmdNQjhHQTFVZEl3UVlNQmFBRkcrdnpmQjFiZWczClVadEpYRXZWOWRNa1hvNmdNQXdHQTFVZEV3UUZNQU1CQWY4d0NnWUlLb1pJemowRUF3SURhUUF3WmdJeEFMUHYKODZFSFRUVElLcEJHdlQrY2NWN3djSC84SFIrc2xhZC9ZUFhLUlZwd2RDbzUyZVRPV3BDS2dGamtHNEJhd1FJeApBTGxGZFgwbEk2ZzhXS3lhRTVmKzJGZEkxYWVqQ0Ftd0xPTTZTRFJhNFVHbitDa2VwOEljeG1CTDIvQmUzSVZ6CjhnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    networks:
      - openid


# 快速建立 auth-doce-client PS: network依佈屬環境為主 docker network ls 確認
#docker run --rm -it \
#  -e HYDRA_ADMIN_URL=https://ory-hydra:4445 \
#  --network openid \
#  oryd/hydra:latest \
#  clients create --skip-tls-verify \
#    --id auth-code-client \
#    --secret secret \
#    --grant-types authorization_code,refresh_token \
#    --response-types code,id_token,token \
#    --scope openid,offline,photos.read \
#    --callbacks https://t.tt:9010/callback

  ory-hydra-login-consent:
    #image: oryd/hydra-login-consent-node:latest
    build:
      context: hydra-login-consent-node/
    restart: unless-stopped
    ports:
      - "9020:3000"
    environment:
      - HYDRA_ADMIN_URL=https://ory-hydra:4445
      - NODE_TLS_REJECT_UNAUTHORIZED=0
    volumes:
      - hydraloginconsent:/usr/src/app:rw
    depends_on:
      - mariadb
    networks:
      - openid
  
  mariadb:
    image: mariadb:10.4.6
    #restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_DATABASE=openid
    command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']
    #第一次使執行db_init_sql.txt
    networks:
      - openid

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
    depends_on:
      - mariadb
    networks:
      - openid

volumes:  
  hydradata: 
  hydraloginconsent:
    
networks:
  openid:
    driver: bridge


Use adminer test maraidb: http://192.168.99.100:8080 root/secret


mariadb init


DROP DATABASE IF EXISTS `openid`;
CREATE DATABASE `openid` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
USE `openid`;

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `password` text COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `user` (`id`, `name`, `email`, `password`) VALUES
(1, 'foobar', 'foo@bar.com', '3858f62230ac3c915f300c664312c63f');

ory-hydra-login-consent modify package.json add


"md5": "^2.2.1",
"mysql": "^2.17.1"

ory-hydra-login-consent add db/database.js


var mysql = require('mysql');

var pool = mysql.createPool({
  host     : 'mariadb',
  user     : 'root',
  password : 'secret',
  database: 'openid'
});

var query=function(sql,options,callback){  
  pool.getConnection(function(err,conn){  
    pool.query
    if(err){  
      callback(err,null,null);  
    }else{  
      conn.query(sql,options,function(err,results,fields){  
        //释放连接  
        conn.release();  
        //事件驱动回调  
        callback(err,results,fields);  
      });  
    }  
  });  
}; 

module.exports = {query, pool}

ory-hydra-login-consent modify routes/login.js


...

router.post('/', csrfProtection, function (req, res, next) {
  // The challenge is now a hidden input field, so let's take it from the request body instead
  var challenge = req.body.challenge;

  var sql = "select count(*) as count from user where email = ? and password = ?"
  var params = [req.body.email, md5(req.body.password)]
  //db.get(sql, params, (err, row) => {
  pool.query(sql, params, (err, row) => {
    if (err) {
      res.status(400).json({"db error":err.message});
      return;
    }

    if(!(row.count==1)){ //找不到
      res.render('login', {
        csrfToken: req.csrfToken(),
  
        challenge: challenge,
  
        error: 'The username / password combination is not correct'
      });
      return;
    }

    hydra.acceptLoginRequest(challenge, {
      // Subject is an alias for user ID. A subject can be a random string, a UUID, an email address, ....
      subject: req.body.email,
  
      // This tells hydra to remember the browser and automatically authenticate the user in future requests. This will
      // set the "skip" parameter in the other route to true on subsequent requests!
      remember: Boolean(req.body.remember),
  
      // When the session expires, in seconds. Set this to 0 so it will never expire.
      remember_for: 3600,
  
      // Sets which "level" (e.g. 2-factor authentication) of authentication the user has. The value is really arbitrary
      // and optional. In the context of OpenID Connect, a value of 0 indicates the lowest authorization level.
      // acr: '0',
    })
    .then(function (response) {
      // All we need to do now is to redirect the user back to hydra!
      res.redirect(response.redirect_to);
    })
    // This will handle any error that happens when making HTTP calls to hydra
    .catch(function (error) {
      next(error);
    });

  });

  // Let's check if the user provided valid credentials. Of course, you'd use a database or some third-party service
  // for this!
  // if (!(req.body.email === 'foo@bar.com' && req.body.password === 'foobar')) {
  //   // Looks like the user provided invalid credentials, let's show the ui again...

  //   res.render('login', {
  //     csrfToken: req.csrfToken(),

  //     challenge: challenge,

  //     error: 'The username / password combination is not correct'
  //   });
  //   return;
  // }

  // Seems like the user authenticated! Let's tell hydra...
  // hydra.acceptLoginRequest(challenge, {
  //   // Subject is an alias for user ID. A subject can be a random string, a UUID, an email address, ....
  //   subject: 'foo@bar.com',

  //   // This tells hydra to remember the browser and automatically authenticate the user in future requests. This will
  //   // set the "skip" parameter in the other route to true on subsequent requests!
  //   remember: Boolean(req.body.remember),

  //   // When the session expires, in seconds. Set this to 0 so it will never expire.
  //   remember_for: 3600,

  //   // Sets which "level" (e.g. 2-factor authentication) of authentication the user has. The value is really arbitrary
  //   // and optional. In the context of OpenID Connect, a value of 0 indicates the lowest authorization level.
  //   // acr: '0',
  // })
  //   .then(function (response) {
  //     // All we need to do now is to redirect the user back to hydra!
  //     res.redirect(response.redirect_to);
  //   })
  //   // This will handle any error that happens when making HTTP calls to hydra
  //   .catch(function (error) {
  //     next(error);
  //   });

  // You could also deny the login request which tells hydra that no one authenticated!
  // hydra.rejectLoginRequest(challenge, {
  //   error: 'invalid_request',
  //   error_description: 'The user did something stupid...'
  // })
  //   .then(function (response) {
  //     // All we need to do now is to redirect the browser back to hydra!
  //     res.redirect(response.redirect_to);
  //   })
  //   // This will handle any error that happens when making HTTP calls to hydra
  //   .catch(function (error) {
  //     next(error);
  //   });
});

https://t.tt:9010 When login id/pwd, can use adminer change database user email/password.

OpenID hydra docker-compose


docker-compose

version: '3.3'

services:
  ory-hydra-postgres:
    image: postgres:9.6
    #restart: always
    environment:
      - POSTGRES_USER=hydra
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=hydra
    volumes:
      - hydradata:/var/lib/postgresql/data:rw
    networks:
      - openid

# 第一次執行postgres要做資料庫格式建立 PS: network依佈屬環境為主 docker network ls 確認
# docker run -it --rm \
#   --network openid \
#   oryd/hydra:latest \
#   migrate sql --yes postgres://hydra:secret@ory-hydra-postgres:5432/hydra?sslmode=disable

  ory-hydra:
    image: oryd/hydra:latest
    restart: unless-stopped
    ports:
      - "9001:4444"
      - "9002:4445"
    environment:
      - SECRETS_SYSTEM=this_needs_to_be_the_same_a
      - DSN=postgres://hydra:secret@ory-hydra-postgres:5432/hydra?sslmode=disable
      - URLS_SELF_ISSUER=https://openid.hydra:9001/
      - URLS_CONSENT=http://192.168.99.100:9020/consent
      - URLS_LOGIN=http://192.168.99.100:9020/login
      - LOG_LEVEL=debug
      - OAUTH2_EXPOSE_INTERNAL_ERRORS=true
      - SERVE_PUBLIC_CORS_ENABLED=true
      - SERVE_PUBLIC_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE
      - SERVE_ADMIN_CORS_ENABLED=true
      - SERVE_ADMIN_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE
      - SERVE_TLS_KEY_BASE64=LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJZz09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUlHa0FnRUJCRENLbkdnVnFJVzdZaW5iUWV5UEd5UTQ0R3U2VVFEelU5SENLYjMzTWlmeFJYRTBkbnU2KzdadQowdEJUcUhQRHVMeWdCd1lGSzRFRUFDS2haQU5pQUFSbng1Nk9jeGNyRWRsYmU4TXRSdUVxWGV2OEREcmh6ZWJGCjM4NlI4Q2RQWDRlUWI2Zll6ekFUL3V3STBsTDdvRmlEWEM3Q0JLWmZUcTdFSzN4TzNXWlpSSjJrMEQ3TnNLd2cKVEpZenJxT0JpczBNeGtva2FUWVVyemhKMXBKY3lmWT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
      - SERVE_TLS_CERT_BASE64=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNQVENDQWNLZ0F3SUJBZ0lKQU13RjRiVDRvSnh0TUFvR0NDcUdTTTQ5QkFNQ01Gd3hDekFKQmdOVkJBWVQKQWtGVk1STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbgphWFJ6SUZCMGVTQk1kR1F4RlRBVEJnTlZCQU1NREc5d1pXNXBaQzVvZVdSeVlUQWVGdzB4T1RBMk1UY3dNVEl4Ck16ZGFGdzB5T1RBMk1UUXdNVEl4TXpkYU1Gd3hDekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJREFwVGIyMWwKTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXhGVEFUQmdOVgpCQU1NREc5d1pXNXBaQzVvZVdSeVlUQjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkdmSG5vNXpGeXNSCjJWdDd3eTFHNFNwZDYvd01PdUhONXNYZnpwSHdKMDlmaDVCdnA5alBNQlArN0FqU1V2dWdXSU5jTHNJRXBsOU8KcnNRcmZFN2RabGxFbmFUUVBzMndyQ0JNbGpPdW80R0t6UXpHU2lScE5oU3ZPRW5Xa2x6SjlxTlFNRTR3SFFZRApWUjBPQkJZRUZHK3Z6ZkIxYmVnM1VadEpYRXZWOWRNa1hvNmdNQjhHQTFVZEl3UVlNQmFBRkcrdnpmQjFiZWczClVadEpYRXZWOWRNa1hvNmdNQXdHQTFVZEV3UUZNQU1CQWY4d0NnWUlLb1pJemowRUF3SURhUUF3WmdJeEFMUHYKODZFSFRUVElLcEJHdlQrY2NWN3djSC84SFIrc2xhZC9ZUFhLUlZwd2RDbzUyZVRPV3BDS2dGamtHNEJhd1FJeApBTGxGZFgwbEk2ZzhXS3lhRTVmKzJGZEkxYWVqQ0Ftd0xPTTZTRFJhNFVHbitDa2VwOEljeG1CTDIvQmUzSVZ6CjhnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    networks:
      - openid
    #這行非常重要,docker成功運行後,要進geht console執行 admin.addPeer("enode://444a16729d32431bbdaa594272e3509cdeaaf3c995ffb583589163d35f8b36ad14394ab037ac186525f579700e6500cacfb1f953fdf066fa05da0e1d409f7f79@140.110.18.199:30301")

  ory-hydra-login-consent:
    #image: oryd/hydra-login-consent-node:latest
    build:
      context: hydra-login-consent-node/
    restart: unless-stopped
    ports:
      - "9020:3000"
    environment:
      - HYDRA_ADMIN_URL=https://ory-hydra:4445
      - NODE_TLS_REJECT_UNAUTHORIZED=0
    volumes:
      - hydraloginconsent:/usr/src/app:rw
    networks:
      - openid

# 快速建立 auth-doce-client PS: network依佈屬環境為主 docker network ls 確認
#docker run --rm -it \
#  -e HYDRA_ADMIN_URL=https://ory-hydra:4445 \
#  --network openid \
#  oryd/hydra:latest \
#  clients create --skip-tls-verify \
#    --id auth-code-client \
#    --secret secret \
#    --grant-types authorization_code,refresh_token \
#    --response-types code,id_token,token \
#    --scope openid,offline,photos.read \
#    --callbacks https://t.tt:9010/callback

volumes:  
  hydradata: 
  hydraloginconsent:
    
networks:
  openid:
    driver: bridge

ory-hydra-login-consent download

https://github.com/ory/hydra-login-consent-node
Directory name is hydra-login-consent-node


go run main.go

https://sueboy.blogspot.com/2019/06/openid-hydra-cant-finish-error.html


Broswer https://t.tt:9010

9-HyperLedger-Fabric原理-MSP详解(一)-MSP基础

https://zhuanlan.zhihu.com/p/35683522

Helm charts for running and operating Hyperledger Fabric in Kubernetes

https://github.com/apggroeifabriek/pivt

hyperledger crypetogen

https://hyperledger-fabric.readthedocs.io/en/release-1.4/commands/cryptogen.html

cryptogen is an utility for generating Hyperledger Fabric key material. It is provided as a means of preconfiguring a network for

testing purposes

. It would normally not be used in the operation of a production network.

Firebase auth and upload image

bootstrap + web firebase realtime + firebase storage

Auth:Use Email&password then input one user with email & password. Login use be added user.

index.html


<!doctype html>
<html lang="zh-Hant-TW">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/4.0.0/firebaseui.css" />

    <title>Hello, world!</title>
  </head>
  <body>
    <div class="container">
        <div id="firebaseui-auth-container" class="alert alert-light" role="alert"></div>
    </div>
    
    <div class="container my-1">
        <div class="row">
            <div class="col-sm">Login Status
                <div class="user-signed-in" style="display: none;"><span class="badge badge-pill badge-success">user-signed-in</span></div>
                <div class="user-signed-out" style="display: none;"><span class="badge badge-pill badge-secondary">user-signed-out</span></div>
            </div>
            <div class="col-sm"><a class="btn btn-outline-primary" data-toggle="collapse" href="#multiCollapseExample1" role="button" aria-expanded="false" aria-controls="multiCollapseExample1">Account Details</a>
                <div class="collapse multi-collapse" id="multiCollapseExample1">
                    <div class="card card-body">
                        <pre id="account-details">...</pre>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="container my-1">
        <div class="row justify-content-end">
            <div class="col-2">
                <div id="sign-in" class="btn btn-outline-primary" style="display: none;">sign-in</div>
                <div id="sign-out" class="btn btn-outline-danger" style="display: none;">sign-out</div>
            </div>
        </div>
    </div>

    <div class="container my-1">
        <div class="row justify-content-center">
            <div id="loading" class="spinner-border" role="status">
                <span class="sr-only">Loading...</span>
            </div>
        </div>
    </div>
    
    <div class="container my-1">
        <div id="loaded" class="user-signed-in" style="display: none;">檔案上傳
            <div id="filesubmit">
                <input type="file" class="file-select" accept="image/*"/>
                <button class="file-submit">SUBMIT</button>
            </div>
        </div>
    </div>

    <div class="container my-1">
        <div class="row">
            <div class="col-2">
                <div id="test" class="btn btn-outline-primary">test</div>
            </div>
        </div>
    </div>
    
        <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <script src="https://cdn.firebase.com/libs/firebaseui/4.0.0/firebaseui.js"></script>
    <script src="https://www.gstatic.com/firebasejs/ui/4.0.0/firebase-ui-auth__zh_tw.js"></script>

    <script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-app.js"></script>
    <script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-auth.js"></script>
    <script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-database.js"></script>
    <!--<script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-firestore.js"></script>-->
    <script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-storage.js"></script>
    
    <script defer src="./init-firebase.js"></script>
    <script>
        
    </script>
    <script>
        document.getElementById('test').addEventListener('click', function() {
            var fbdbpath = getfbdbPath('images/@/default/');
            putimageurl(fbdbpath, 'url');
        });
        
        function fileupload(){ //== File upload ========================
            document.querySelector('.file-select').addEventListener('change', handleFileUploadChange);
            document.querySelector('.file-submit').addEventListener('click', handleFileUploadSubmit);
            
            let selectedFile;

            function handleFileUploadChange(e) {
                selectedFile = e.target.files[0];
            }

            function handleFileUploadSubmit(e) {
                var metadata = {
                    contentType: 'image/jpeg'
                };

                var fbdbpath = getfbdbPath('images/@/default/');
                var newfbdbPostKey= getfbdbPostKey(fbdbpath);
                var uploadTask = imagesRef.child(`${newfbdbPostKey}`).put(selectedFile, metadata);

                uploadTask.on('state_changed', function(snapshot){
                    var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
                    console.log('Upload is ' + progress + '% done');
                    switch (snapshot.state) {
                        case firebase.storage.TaskState.PAUSED: // or 'paused'
                        console.log('Upload is paused');
                        break;
                        case firebase.storage.TaskState.RUNNING: // or 'running'
                        console.log('Upload is running');
                        break;
                    }
                    }, function(error) {
                        // Handle unsuccessful uploads
                        alert('Upload is Failed;');
                        console.log(error);
                    }, function() {
                        uploadTask.snapshot.ref.getDownloadURL().then(function(downloadURL) {
                            console.log('File available at', downloadURL);
                            putimageurl(fbdbpath, downloadURL);
                        });
                    }
                );
            }
        }


        function initsign(){ //== Auth ===============================
            document.getElementById('sign-in').addEventListener('click', function() {
                if($('.user-signed-out').css('display') === 'block') ui.start('#firebaseui-auth-container', getUiConfig());
            });

            document.getElementById('sign-out').addEventListener('click', function() {
                var user = firebase.auth().currentUser;

                if (user) {
                    firebase.auth().signOut().then((res)=>{
                        console.log('signOut ok', res);
                    }).catch((err)=>{
                        alert('Logout Failed!');
                        console.warn('signOut error',res);
                    }).finally((res)=>{
                        console.log('signOut resolved', res);
                        location.reload();
                    });
                }
            });
        }

    </script>

  </body>
</html>


init-firebase.js


var firebaseConfig  = {
  apiKey: 'AIzaSyBxxxxxxooooo',
  authDomain: 'product-xxxxxxooooo.firebaseapp.com',
  databaseURL: 'https://product-xxxxxxooooo.firebaseio.com',
  storageBucket: 'gs://product-xxxxxxooooo.appspot.com'
};
firebase.initializeApp(firebaseConfig);

//== database ===========================
var database = firebase.database();

function getfbdbPath(type){
  var userId = firebase.auth().currentUser.uid;
  return type.replace("@", userId);
}

function getfbdbPostKey(path){
  return firebase.database().ref().child(path).push().key;
}

function putimageurl(path, url){
  //var userId = firebase.auth().currentUser.uid;
  var path = getfbdbPath('images/@/default/');
  var postImg = {
    active: true,
    url: url,
  };

  var newPostKey = getfbdbPostKey(path);
  var images = {};
  images[path + newPostKey] = postImg;
  //updates['/user-posts/' + userId + '/' + newPostKey] = postData;

  var uploadImagesResult = firebase.database().ref().update(images);
  console.log('uploadImagesResult');
  console.log(uploadImagesResult);
}

function test(){
  var userId = firebase.auth().currentUser.uid;

  firebase.database().ref('users/' + userId).set({
    username: 'name',
    email: 'email',
    profile_picture : 'imageUrl'
  }, function(error) {
    if (error) {
      console.log(error)
      // The write failed...
    } else {
      // Data saved successfully!
      console.log("successfullly!")
    }
  });

  var c = firebase.database().ref('/users/' + userId).once('value').then(function(snapshot) {
    var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
    // ...
    console.log("username:", username);
  });
  console.log('c');
  console.log(c);

  var postData = {
    author: 'username',
    uid: userId,
  };
  var newPostKey = firebase.database().ref().child('posts').push().key;
  var updates = {};
  updates['/posts/' + newPostKey] = postData;
  //updates['/user-posts/' + userId + '/' + newPostKey] = postData;
  //firebase.database().ref('posts/' + userId).set(postData);

  var t = firebase.database().ref().update(updates);
  console.log('t');
  console.log(t);
}


//== File upload ========================
var storageRef = firebase.storage().ref();
var imagesRef = storageRef.child('images');

// var otherProject = firebase.initializeApp(firebaseConfig, 'other');
// console.log(otherProject.name);    // "otherProject"
// var otherStorage = otherProject.storage();

//== Auth ===============================
function getUiConfig() {
  return {
    signInSuccessUrl: this.location.href,
    signInOptions: [
      firebase.auth.EmailAuthProvider.PROVIDER_ID,
    ],
    //immediateFederatedRedirect: false,
  };
}

// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
// The start method will wait until the DOM is loaded.
if (ui.isPendingRedirect()) {
  ui.start('#firebaseui-auth-container', getUiConfig());
}
// Disable auto-sign in.
// ui.disableAutoSignIn();

var handleSignedInUser = function(user) {
  $('.user-signed-in').show();
  $('.user-signed-out').hide();
  $('#sign-in').hide();
  $('#sign-out').show();
  document.getElementById('account-details').textContent = user.displayName;
  user.getIdToken().then(function(accessToken) {
    document.getElementById('account-details').textContent = 
      JSON.stringify({
        displayName: user.displayName,
        email: user.email,
        emailVerified: user.emailVerified,
        phoneNumber: user.phoneNumber,
        photoURL: user.photoURL,
        uid: user.uid,
        accessToken: user.accessToken,
        providerData: user.providerData
      }, null, '  ');
  });
};

var handleSignedOutUser = function() {
  $('.user-signed-in').hide();
  $('.user-signed-out').show();
  $('#sign-in').show();
  $('#sign-out').hide();
  //ui.start('#firebaseui-container', getUiConfig());
};

function handleConfigChange() {
  // Reset the inline widget so the config changes are reflected.
  ui.reset();
  ui.start('#firebaseui-container', getUiConfig());
}

firebase.auth().onAuthStateChanged(function(user) {
  document.getElementById('loading').style.display = 'none';
  document.getElementById('loaded').style.display = 'block';
  user ? handleSignedInUser(user) : handleSignedOutUser();
}, function(error) {
  console.log(error);
});

initsign();
fileupload();


firebase realtime database rule

95dWpHhg5wOk1loIj0iTneWdfwG2 is admin user <= userId = firebase.auth().currentUser.uid;

{
"rules": {
".read": "'95dWpHhg5wOk1loIj0iTneWdfwG2' === auth.uid",
"users": {
"$uid": {
".write": "$uid === auth.uid"
}
},
"images": {
".write": "'95dWpHhg5wOk1loIj0iTneWdfwG2' === auth.uid",
}
}
}


firebase storage rule

95dWpHhg5wOk1loIj0iTneWdfwG2 is admin user <= userId = firebase.auth().currentUser.uid;

rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read;
allow write: if '95dWpHhg5wOk1loIj0iTneWdfwG2' == request.auth.uid;
}
}
}

[轉]PoA private network clique: 😱 block lost

https://github.com/ethereum/go-ethereum/issues/18405

That's generally fine. The way clique works is that the in-turn sealer who should ideally sign next tries to sign and propagate the block immediately when the timer ticks. If no in-turn block appears within 500ms, the other signers start potentially creating alternative blocks (with random delays), this ensures that even if a signer is missing, the chain progresses more or less properly.

Now, if the original in-turn signer does come around and publish its block with some delay, that might reorg out alternative blocks signer by out-of-turn signers. At that point those will complain that their block was lost. The scary smiley is mostly meant for ethash :) Clique blocks have no subsidy anyway :)

How to use Makefile in docker-machine

https://stackoverflow.com/questions/34624510/how-to-use-makefile-in-docker-machine


tce-load -wi make

ethereum geth keystore -> private key -> address (check)

Use keythereum, web3


npm install keythereum
npm install web3


.datadir need to correct.
UTC/keystore/UTC--2019-03-25T09-10-35.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
.address need correct "0xooooooooooooooooooooooooo"
.password need correct, this example is empty.
.web3 localhost is fake, don't need have geth.


var keythereum = require("keythereum");
var datadir = "UTC";
var address= "0xooooooooooooooooooooooooo";
const password = "";

var keyObject = keythereum.importFromFile(address, datadir);
var privateKey = keythereum.recover(password, keyObject);
console.log(privateKey.toString('hex'));

Web3 = require('web3')
web3 = new Web3(new Web3.providers.HttpProvider("localhost"));  
var address = web3.eth.accounts.privateKeyToAccount("0x"+privateKey.toString('hex'));
console.log(address);

[轉]Go面向对象编程以及在Tendermint/Cosmos-SDK中的应用

https://segmentfault.com/a/1190000019776978

Firebase Database Rules

https://www.oxxostudio.tw/articles/201904/firebase-realtime-database-rules.html

https://angularfirebase.com/lessons/understanding-firebase-database-rules-by-example/

ethereum Solidity v0.5.0 Breaking Changes

https://solidity.readthedocs.io/en/v0.5.0/050-breaking-changes.html#example
https://github.com/ethereum/solidity/blob/develop/Changelog.md

[轉]以太坊智能合约Solidity 0.5.0版本重大变化

https://zhuanlan.zhihu.com/p/54169418


随着solidity 0.5.0 nightly build版本的稳步推进,正式版也将在不久的将来与开发者见面.作为一个大版本更新,新版引入了很多特性,也废弃了很多关键字,比如

.call()不仅可以获知远程调用执行成功与否,还将获得远程调用执行的返回值
ABI解码做了新的处理规范,有效防御了"短地址攻击"
address地址类型细分成 address和 address payable
uintY和 bytesX不能直接转换
回退函数必须显式声明为 external可见性
构造函数必须用 constructor关键字定义
用于抛出异常的 throw关键字弃用, 函数状态可变性修饰符必须用 view,不能混用 constant和 view
...
下面我们将对这些改变一一予以介绍,最后给出一个示例代码,对比展示新旧版solidity代码写法的区别,供大家参考.

显式声明
函数可见性
函数可见性必须显式声明. 之前, 函数如果不显式声明,将默认 public可见性.
public: constructor构造函数必须声明为 public可见性,否则编译报错.
external: 回退函数(fallback function), 接口(interface)的函数必须声明为 external可见性,否则编译报错.
存储位置
结构体(struct),数组(array),映射(mapping)类型的变量必须显式声明存储位置( storage, memeory, calldata),包括函数参数和返回值变量都必须显式声明.
external 的函数参数需显式声明为 calldata.
合约与地址
contract合约类型不再包括 address类型的成员函数,必须显式转换成 address地址类型才能使用 send(), transfer(), balance等与之相关的成员函数/变量成员.
address地址类型细分为 address和 address payable,只有 address payable可以使用 transfer(), send()函数.
address payable类型可以直接转换为 address类型, 反之不能.
但是 address x可以通过 address(uint160(x)),强制转换成 address payable类型.
如果 contract A不具有 payable的回退函数, 那么 address(A)是 address类型.
如果 contract A具有 payable的回退函数, 那么 address(A)是 address payable类型.
msg.sender属于 address payable类型.
转换与填充(padding)
uintY与 bytesX
因为填充(padding)的时候, bytesX是右填充(低比特位补0),而 uintY是左填充(高比特位补0),二者直接转换可能会导致不符合预期的结果,所以现在当 bytesX和 uintY长度大小不一致(即X*8 != Y)时,不能直接转换,必须先转换到相同长度,再转换到相同类型.
10进制数值不能直接转换成 bytesX类型, 必须先转换到与 bytesX相同长度的 uintY,再转换到 bytesX类型
16进制数值如果长度与 bytesX不相等,也不能直接转换成 byteX类型
ABI
字面值必须显式转换成类型才能使用 abi.encodePacked()
ABI编码器在构造外部函数入参和 abi.encode()会恰当地处理 bytes和 string类型的填充(padding),若不需要进行填充,请使用 abi.encodePacked()
ABI解码器在解析函数入参和 abi.decode()时,如果发现 calldata太短或超长,将直接抛出异常,而不是像之前自动填充(补0)和截断处理,从而有效地遏制了短地址攻击.
.call()族函数( .call(), .delegatecall(), .staticcall())和 哈希函数( keccak256(), sha256(), ripemd160())只接受一个参数 bytes,且不进行填充(padding)处理.
.call()空参数必须写成 .call("")
.call(sig,a,b,c)必须写成 .call(abi.encodeWithSignature(sig,a,b,c)),其他类推
keccak256(a,b,c)必须写成 keccak256(abi.encodePacked(a,b,c)),其他类推
另外, .call()族函数之前只返回函数执行成功是否的 bool, 现在还返回函数执行的返回值,即 (bool,bytes memory). 所以之前 boolresult=.call(sig,a,b,c)现在必须写成 (boolresult,bytes memory data)=.call(sig,a,b,c).
不允许的写法
在之前版本的solidity编译,以下不允许的写法只会导致 warnings报警,现在将直接 errors报错.

不允许声明0长度的定长数组类型.
不允许声明0结构体成员的结构体类型.
不允许声明未初始化的 storage变量.
不允许定义具有命名返回值的函数类型.
不允许定义非编译期常量的 constant常量. 如 uintconstant time=now;是不允许的.
不允许 0X(X大写)做16进制前缀,只能用 0x.
不允许16进制数和单位名称组合使用. 如 value=0xffether必须写成 value=0xff*1ether.
不允许小数点后不跟数字的数值写法. 如 value=255.0ether不能写成 value=255.ether.
不允许使用一元运算符 +. 例如 value=1ether不能写成 value=+1ether.
不允许布尔表达式使用算术运算.
不允许具有一个或多个返回值的函数使用空返回语句.
不允许未实现的函数使用修饰符(modifier).
不允许 msg.value用在非 payable函数里以及此函数的修饰符(modifier)里.
废弃的关键字/函数
years时间单位已弃用,因为闰年计算容易导致各种问题.
var已弃用,请用 uintY精确声明变量长度.
constant函数修饰符已弃用,不能用作修饰函数状态可变性, 请使用 view关键字.
throw关键字已弃用,请使用 revert(), require(), assert()抛出异常.
.callcode()已弃用,请使用 .delegatecall(). 但是注意,在内联汇编仍可使用.
suicide()已弃用, 请使用 selfdestruct().
sha3()已弃用,请使用 keccak256().
构造函数
构造函数必须用 constructor关键字定义. 之前,并未强制要求,既可以用合约同名函数定义构造函数,也可以用 constructor关键字定义.
不允许调用没有括号的基类构造函数.
不允许在同一继承层次结构中多次指定基类构造函数参数.
不允许调用带参数但具有错误参数计数的构造函数.如果只想在不提供参数的情况下指定继承关系,请不要提供括号.
其他
do...while循环里的 continue不再跳转到循环体内,而是跳转到 while处判断循环条件,若条件为假,就退出循环.这一修改更符合一般编程语言的设计风格.
实现了C99风格的作用域:
变量必须先声明,后使用.之前,是可以先使用,后声明,现在会导致编译报错.
只能在相同或嵌套作用域使用.比如 if(){...}, do{...}while();, for{...}块内声明的变量,不能用在块外.
变量和结构体的循环依赖递归限制在256层.
pure和 view函数在EVM内部采用 staticcall操作码实现(EVM版本>=拜占庭),而非之前的 call操作码,这使得状态不可更改(state changes disallowed)在虚拟机层面得到保证


示例



以下示例显示了Solidity v0.5.0的合约及其更新版本,其中包含本节中列出的一些更改。

旧版:


// 这个不能编译
pragma solidity ^0.4.25;
contract OtherContract {
   uint x;
   function f(uint y) external {
      x = y;
   }
   function() payable external {}
}

contract Old {
   OtherContract other;
   uint myNumber;

   //没有提供函数可变性,不是错误。
   function someInteger() internal returns (uint) { return 2; }

//未提供功能可见性,不是错误。
  //没有提供函数可变性,不是错误。
   function f(uint x) returns (bytes) {
      // Var 可以用
      var z = someInteger();
      x += z;
      // Throw 可以用
      if (x > 100)
         throw;
      bytes b = new bytes(x);
      y = -3 >> 1;
      // y =-2
      do {
         x += 1;
         if (x > 10) continue;
         //'继续'会导致无限循环。
      } while (x < 11);
      // 返回bool
      bool success = address(other).call("f");
      if (!success)
         revert();
      else {
         //可以在使用后声明局部变量。
         int y;
      }
      return b;
   }

   //不需要'arr'的显式数据位置
   function g(uint[] arr, bytes8 x, OtherContract otherContract) public {
      otherContract.transfer(1 ether);

//由于uint32(4字节)小于bytes8(8字节),
   //  x的前4个字节将丢失。 这可能会导致
   // 由于bytesX是右填充的意外行为。      
uint32 y = uint32(x);
      myNumber += y + msg.value;
   }
}

新版本:

pragma solidity >0.4.99 <0.6.0;
contract OtherContract {
   uint x;
   function f(uint y) external {
      x = y;
   }
   function() payable external {}
}

contract New {
   OtherContract other;
   uint myNumber;

   //必须指定函数可变性。
   function someInteger() internal pure returns (uint) { return 2; }

  //必须指定功能可见性。
     //必须指定函数可变性。
   function f(uint x) public returns (bytes memory) {
      //现在必须明确给出类型。
      uint z = someInteger();
      x += z;
      // Throw 不允许
      require(x > 100);
      int y = -3 >> 1;
      // y == -2 (正确)
      do {
         x += 1;
         if (x > 10) continue;
         //'继续'跳到下面的条件。
      } while (x < 11);
//调用返回(bool,bytes)。
      // 必须指定数据位置。
      (bool success, bytes memory data) = address(other).call("f");
      if (!success)
         revert();
      return data;
   }

   using address_make_payable for address;
   //必须指定'arr'的数据位置
   function g(uint[] memory arr, bytes8 x, OtherContract otherContract, address unknownContract)
 public payable {
      // 未提供“otherContract.transfer”。
      //由于'OtherContract'的代码是已知的并具有后备
      // function,address(otherContract)的类型为“地址应付”。
      address(otherContract).transfer(1 ether);
    //未提供'unknownContract.transfer'。
//未提供'address(unknownContract).transfer'
//因为'地址(unknownContract)'不是'地址应付'。
//如果该函数采用您要发送的“地址”
//资金到,您可以通过'uint160'将其转换为'地址应付'。
//注意:不建议使用此类型和显式类型
//应尽可能使用“应付地址”。
//为了提高清晰度,我们建议使用库
//转换(在本例中的合同之后提供)。
      address payable addr = unknownContract.make_payable();
      require(addr.send(1 ether));
//由于uint32(4字节)小于bytes8(8字节),
//不允许转换。
//我们需要先转换为通用尺寸:
      bytes4 x4 = bytes4(x); //填充发生在右侧
      uint32 y = uint32(x4); //转换是一致的
//'msg.value'不能用于'非应付'功能。
//我们需要支付功能
      myNumber += y + msg.value;
   }
}
//我们可以定义一个库来显式转换``address``
//将``地址应付款``作为一种解决方法。
library address_make_payable {
   function make_payable(address x) internal pure returns (address payable) {
      return address(uint160(x));
   }
}

Material Design Lite google

https://github.com/google/material-design-lite

希望香港不要踩底線啊~~

中共的底線港獨是不能碰,打砸搶也不行,平和抗議示威肯定可以,希望香港不要踩底線啊~~

https://www.youtube.com/watch?v=HAP3QCgD6YA 郭文貴資助梁頌恆搞港獨(美國) -- 錢、簽證、政治保護都準備好了

https://youtu.be/-FuVqqPCy98?list=FLGJ0IWhI8tRS57Y4rmEu1HA&t=695 六四 美國 -- 護照

https://www.youtube.com/watch?v=Y3AUKmNorPQ&list=FLGJ0IWhI8tRS57Y4rmEu1HA&index=26&t=0s 寒梅的六四
(這人影片有爭議,但主要看當初留下來的影片和一些資料)

https://youtu.be/SE6g2DVqr_4?list=PLBAD92DFCE1748197&t=235 西藏 美國 CIA介入 提供武器判亂 獨立

https://youtu.be/EM_48sSLS7o?t=303 西藏 嘉樂頓珠 達懶二哥回憶錄 接觸CIA,給支持
與美國中情局的合作,是我一生都懊悔的事情

https://youtu.be/O0fhyJxUcW0?list=FLGJ0IWhI8tRS57Y4rmEu1HA&t=355 香港遠東情報中心 斯諾登 菱鏡計畫


https://zh.wikipedia.org/wiki/%E7%A8%9C%E9%8F%A1%E8%A8%88%E7%95%AB 菱鏡計畫 2007年 美國絕密級網絡監控計劃
https://youtu.be/BrruzdYuZiA?t=55 法國報紙內容
https://www.storm.mg/article/31057 台灣竟也不可免地陷入此一偵監網羅

https://zh.wikipedia.org/wiki/%E9%9C%87%E7%BD%91 震網(Stuxnet) 目標為伊朗使用西門子控制系統的高價值基礎設施
美國官員承認這個病毒是由美國國家安全域在以色列協助下研發,以奧林匹克網路攻擊行動為計劃代號,目的在於阻止伊朗發展核武

【竹老板】大陸人可以批評自己的國家和官員嘛?//批評官員等於愛國嘛?
https://youtu.be/W29_U-Ev8MI?t=177

【竹老板】扯闲篇:墙倒了谁倒霉
https://youtu.be/1Z70CwAiuDc?t=72

https://youtu.be/FiyJf-8lMmo?t=193 德國知事從愛台灣 到 和平統一無望
https://youtu.be/FiyJf-8lMmo?t=980 台灣情 沒防火牆後 的 厭惡