Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - Issue5164 - open backend sources (2fa, multisig, invoices) #5178

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file.
1 change: 1 addition & 0 deletions src/back/swaponline/btcPin/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require("./src/server.js")
Empty file.
34 changes: 34 additions & 0 deletions src/back/swaponline/btcPin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "swap.2fapin.service",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"amocrm-js": "^1.0.4",
"archiver": "^3.0.0",
"axios": "^0.18.0",
"bitcoinjs-lib": "^5.1.6",
"bitcoinjs-message": "^2.1.0",
"body-parser": "^1.18.3",
"express": "^4.16.4",
"highland": "^2.13.0",
"replacestream": "^4.0.3",
"request": "^2.88.0",
"sha3": "^2.1.2",
"sqlite3": "^4.2.0",
"uuid": "^3.3.2",
"uuid-validate": "0.0.3",
"web3": "^1.0.0-beta.37",
"web3-utils": "^1.0.0-beta.41"
},
"devDependencies": {
"mocha": "^5.2.0",
"superagent": "^5.1.0"
}
}
98 changes: 98 additions & 0 deletions src/back/swaponline/btcPin/src/btcutils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const bitcoin = require('bitcoinjs-lib')
const bitcoinMessage = require('bitcoinjs-message')
const config = require("./config.js")
const request = require('superagent')


let _account_mainnet = null
let _account_testnet = null

const login = (privateKeyMainnet, privateKeyTestnet) => {
_account_mainnet = bitcoin.ECPair.fromWIF(privateKeyMainnet, bitcoin.networks.mainnet)
_account_testnet = bitcoin.ECPair.fromWIF(privateKeyTestnet, bitcoin.networks.testnet)
console.log('Logged to bitcoin')
console.log('Testnet:')
console.log(bitcoin.payments.p2pkh({ pubkey: _account_testnet.publicKey, network: bitcoin.networks.testnet }).address)
console.log(_account_testnet.publicKey.toString('hex'))
console.log('Mainnet:')
console.log(bitcoin.payments.p2pkh({ pubkey: _account_mainnet.publicKey, network: bitcoin.networks.mainnet }).address)
console.log(_account_mainnet.publicKey.toString('hex'))
}

const CheckPublicKey = (walletAddress, publicKey, checkSign, mainnet) => {
return true
console.log(checkSign)
const signature = Buffer.from(checkSign, 'base64')
const message = `${walletAddress}:${publicKey}`
console.log(message)
console.log(signature.toString('base64'))
return bitcoinMessage.verify(message, walletAddress, signature)
}

const SignTXv5 = async (publicKey, txHash, mainnet) => {
console.log('SignTXv5', publicKey, txHash)
const network = (mainnet) ? bitcoin.networks.mainnet : bitcoin.networks.testnet
const privateKey = (mainnet) ? config.privateKey.mainnet : config.privateKey.testnet

const psbt = bitcoin.Psbt.fromHex(txHash)

psbt.signAllInputs(bitcoin.ECPair.fromWIF(privateKey, network))
psbt.finalizeAllInputs();

const rawTx = psbt.extractTransaction().toHex()

return rawTx
}

const SignTXv4 = async (publicKey, txHash, mainnet) => {
console.log('SignTX', publicKey, txHash)
const account = (mainnet) ? _account_mainnet : _account_testnet
const network = (mainnet) ? bitcoin.networks.mainnet : bitcoin.networks.testnet
const privateKey = (mainnet) ? config.privateKey.mainnet : config.privateKey.testnet

let publicKeys = JSON.parse(publicKey)
//publicKeys.unshift( account.publicKey.toString('Hex') )

console.log('PublicKeys raw', publicKeys)
publicKeys = publicKeys.map( (key) => Buffer.from(key, 'Hex') )
console.log('pk',publicKeys)

let txb = bitcoin.TransactionBuilder.fromTransaction(
bitcoin.Transaction.fromHex(txHash),
(mainnet) ? bitcoin.networks.mainnet : bitcoin.networks.testnet
);

const p2ms = bitcoin.payments.p2ms({
m: 2,
n: publicKeys.length,
pubkeys: publicKeys,
network
})

const p2sh = bitcoin.payments.p2sh({ redeem: p2ms, network })

txb.__INPUTS.forEach((input, index) => {
txb.sign(index, bitcoin.ECPair.fromWIF(privateKey, network), p2sh.redeem.output)
})

let tx = await txb.build()

return tx.toHex()
}

const broadcast = (txRaw, mainnet) => {
const api = (mainnet) ? config.api.mainnet : config.api.testnet
request.post(`${api}/tx/send`, {
body: {
rawtx: txRaw,
},
})
}

module.exports = {
login,
CheckPublicKey,
SignTXv4,
SignTXv5,
broadcast,
}
12 changes: 12 additions & 0 deletions src/back/swaponline/btcPin/src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* Example */
module.exports = {
privateKey: {
mainnet: 'L14dpjVrqqM7u5sFGGLjGzUfqUYvHAdqPie6xS8k2BytUJsE2xf6',
testnet: 'cS4cbfFjdxMKd2fu3FjMMedT2z5BbzbvuapHu59ArdeAiQtZzJmr',
},
api: {
mainnet: 'https://insight.bitpay.com/api',
testnet: 'https://test-insight.swap.online/insight-api'
},
port: 3000,
}
117 changes: 117 additions & 0 deletions src/back/swaponline/btcPin/src/database.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('./db.sqlite');
const { SHA3 } = require('sha3');

const { CheckPublicKey } = require('./btcutils.js')


let users = {}
/*
users = {
'wallet' => {
'publickKey',
'passhash',
}
}
*/

const save = async () => {

}

const load = async () => {
const createQuery = "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY AUTOINCREMENT, wallet TEXT, public TEXT, passhash TEXT, mainnet INT);";
db.serialize( async () => {
db.run(createQuery)
await db.each('SELECT * FROM users', function(err, row) {

const key = `${row.wallet}:${(row.mainnet) ? 'M' : 'T'}`

let publicKey = row.public

try {
publicKey = JSON.parse(publicKey)
publicKey = JSON.stringify((publicKey instanceof Array) ? publicKey : [publicKey])
} catch (e) {
publicKey = JSON.stringify([publicKey])
}

if (!users[key]) users[key] = []
users[key].push({
address: row.wallet,
publicKey,
passhash: row.passhash,
mainnet: row.mainnet ? true : false
})
}, () => {
console.log('Database loaded. Users: '+Object.keys(users).length)
})
})
}

const getPassHash = (password) => {
const passwordSha = new SHA3(256)
passwordSha.update(password)

return passwordSha.digest('hex')
}
const add = (walletAddress, publicKey, password, checkSign, mainnet) => {
if (CheckPublicKey(walletAddress, publicKey, checkSign, mainnet)) {
const key = `${walletAddress}:${(mainnet) ? 'M' : 'T'}`

const passhash = getPassHash(password)

try {
const publicKeys = JSON.parse(publicKey)
// if ok - new 2of3 or 2of2
} catch (e) {
// old 2of2 and old react builds
publicKey = JSON.stringify([publicKey])
}

if (!users[key]) users[key] = []
users[key].push({
address: walletAddress,
publicKey,
passhash,
})

db.serialize( () => {
const stmt = db.prepare('INSERT INTO users VALUES (?,?,?,?,?)');
stmt.run(null, walletAddress, publicKey, passhash, mainnet ? 1 : 0)
stmt.finalize();
})
return true
} else {
return { error: 'Sign check failed' }
}
}


const exist = (walletAddress, publicKey, mainnet) => {
const key = `${walletAddress}:${(mainnet) ? 'M' : 'T'}`
console.log('>>> key', key)
console.log(users[key])
if (users[key] && users[key].length) {
let result = false
users[key].forEach( (wallet) => {
if (wallet.publicKey == publicKey) {
result = {
passhash: wallet.passhash
}
return false
}
})
return result
}
return false
}

module.exports = {
users,
load,
save,
add,
exist,
getPassHash,
}
Loading