Skip to content
Closed
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
4 changes: 1 addition & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,9 @@ subprojects {
implementation 'org.web3j:core:4.10.3'
implementation 'wf.bitcoin:bitcoin-rpc-client:1.2.4'

implementation "org.springframework.boot:spring-boot-starter-amqp:$springBootVersion"
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
implementation 'com.github.sealedtx:bitcoin-cash-converter:1.0'
implementation 'com.xuxueli:xxl-job-core:2.4.0'
implementation 'com.github.GalaxySciTech:tokencore:1.3.0'
implementation 'com.github.galaxyscitech:tokencore:2.0.0'

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'

Expand Down
3 changes: 1 addition & 2 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@ include(
"wallet-common",
"wallet-entity",
"wallet-webapi",
"wallet-hsm",
"wallet-task"
"wallet-hsm"
)
1 change: 1 addition & 0 deletions wallet-common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ jar.enabled = true

dependencies {
api project(":wallet-entity")
implementation project(":wallet-hsm")
implementation 'commons-codec:commons-codec:1.16.0'
implementation 'org.bitcoinj:bitcoinj-core:0.14.7'
}
12 changes: 10 additions & 2 deletions wallet-common/src/main/kotlin/com/wallet/biz/dict/SysConfigKey.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package com.wallet.biz.dict

/**

* Created by pie on 2020/7/24 18: 50.

DEPOSIT_NOTIFY_MODE("post","充值同步模式,支持 post","充值通知"),
SCHEDULER_DEPOSIT_SCAN_ENABLED("true", "充值扫描任务开关", "任务调度"),
SCHEDULER_DEPOSIT_SCAN_MS("15000", "充值扫描任务间隔毫秒", "任务调度"),
SCHEDULER_CHAIN_SYNC_ENABLED("true", "区块同步任务开关", "任务调度"),
SCHEDULER_CHAIN_SYNC_MS("20000", "区块同步任务间隔毫秒", "任务调度"),
SCHEDULER_SWEEP_ENABLED("false", "归集任务开关", "任务调度"),
SCHEDULER_SWEEP_MS("30000", "归集任务间隔毫秒", "任务调度"),
SCHEDULER_FEE_SUPPLY_ENABLED("false", "手续费补充任务开关", "任务调度"),
SCHEDULER_FEE_SUPPLY_MS("30000", "手续费补充任务间隔毫秒", "任务调度");

*/
enum class SysConfigKey(var defaultValue:String,var description:String,var group:String) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.wallet.biz.mq

import com.fasterxml.jackson.databind.JsonNode
import com.wallet.biz.dict.MqKey
import com.wallet.biz.dict.SysConfigKey
import com.wallet.biz.domain.dict.ErrorCode
import com.wallet.biz.domain.exception.BizException
import com.wallet.biz.log.impl.LogService
import com.wallet.biz.utils.Crypto
import org.springframework.amqp.core.AmqpTemplate
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
Expand All @@ -25,7 +23,7 @@ class PushComponent : LogService() {
}

fun sendMsgToMq(msg: String) {
amqpTemplate.convertAndSend(MqKey.TOPIC_EXCHANGE, MqKey.DEPOSIT_KEY, msg)
sendMsgToService(msg)
}

fun sendMsgToService(msg: String) {
Expand All @@ -39,9 +37,6 @@ class PushComponent : LogService() {
}
}

@Autowired
lateinit var amqpTemplate: AmqpTemplate

@Autowired
lateinit var restTemplate: RestTemplate

Expand Down
162 changes: 14 additions & 148 deletions wallet-common/src/main/kotlin/com/wallet/biz/request/HsmRequest.kt
Original file line number Diff line number Diff line change
@@ -1,163 +1,29 @@
package com.wallet.biz.request

import com.wallet.biz.dict.HsmReuqestType
import com.wallet.biz.dict.SysConfigKey
import com.wallet.biz.domain.dict.ErrorCode
import com.wallet.biz.domain.dict.TokenResponse
import com.wallet.biz.domain.exception.BizException
import com.wallet.biz.domain.po.*
import com.wallet.biz.domain.vo.AddressVo
import com.fasterxml.jackson.databind.ObjectMapper
import org.consenlabs.tokencore.wallet.transaction.BitcoinTransaction
import org.consenlabs.tokencore.wallet.transaction.TxSignResult
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.core.ParameterizedTypeReference
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.stereotype.Component
import org.springframework.web.client.RestTemplate
import java.math.BigDecimal
import java.util.*

/**

* Created by pie on 2019-04-13 16: 01.

*/
@Component
class HsmRequest {

private val logger = LoggerFactory.getLogger(HsmRequest::class.java)

private fun getHsmUrl(): String {
return cacheService.getSysConfig(SysConfigKey.HSM_URL)
}

fun getAllWallets():List<AddressVo>{
return exchange(
"${getHsmUrl()}${HsmReuqestType.GET_ALL_WALLETS}",
HttpMethod.GET,
null,
List::class.java
)
.map { obj.readValue(obj.writeValueAsString(it), AddressVo::class.java) }
}

fun deriveWallets(chainTypes: List<String>): List<AddressVo> {
return exchange(
"${getHsmUrl()}${HsmReuqestType.DERIVE_WALLETS}",
HttpMethod.POST,
chainTypes,
List::class.java
)
.map { obj.readValue(obj.writeValueAsString(it), AddressVo::class.java) }
return hsmXService.getAllWallets()
}

fun signUsdtTransaction(
utxos: ArrayList<BitcoinTransaction.UTXO>,
amount: BigDecimal,
fee: BigDecimal,
toAddress: String,
walletId: String
): TxSignResult {
val signUsdtPo = SignUsdtPo()
signUsdtPo.utxos = utxos
signUsdtPo.amount = amount
signUsdtPo.fee = fee
signUsdtPo.toAddress = toAddress
signUsdtPo.walletId = walletId
return exchange(
"${getHsmUrl()}${HsmReuqestType.SIGN_USDT_TRANSACTION}",
HttpMethod.POST,
signUsdtPo,
TxSignResult::class.java
)
}

fun signBtcTransaction(
amount: BigDecimal,
fee: BigDecimal,
toAddress: String,
utxos: ArrayList<BitcoinTransaction.UTXO>,
walletId: String
): TxSignResult {
val signBitcoinPo = SignBitcoinPo()
signBitcoinPo.utxos = utxos
signBitcoinPo.amount = amount
signBitcoinPo.fee = fee
signBitcoinPo.toAddress = toAddress
signBitcoinPo.walletId = walletId
return exchange(
"${getHsmUrl()}${HsmReuqestType.SIGN_BTC_TRANSACTION}",
HttpMethod.POST,
signBitcoinPo,
TxSignResult::class.java
)
}

fun signEthtransaction(
nonce: Int,
amount: BigDecimal,
gasPrice: BigDecimal,
gasLimit: Long,
toAddress: String,
walletId: String,
data: String?
): TxSignResult {
val signEthereumPo = SignEthereumPo()
signEthereumPo.walletId = walletId
signEthereumPo.amount = amount
signEthereumPo.toAddress = toAddress
signEthereumPo.nonce = nonce
signEthereumPo.gasPrice = gasPrice
signEthereumPo.data = data
signEthereumPo.gasLimit = gasLimit
return exchange(
"${getHsmUrl()}${HsmReuqestType.SIGN_ETH_TRANSACTION}",
HttpMethod.POST,
signEthereumPo,
TxSignResult::class.java
)
}

fun signUsdtCollectTransaction(
toAddress: String,
amount: BigDecimal,
fee: BigDecimal,
utxos: ArrayList<BitcoinTransaction.UTXO>,
feeProviderUtxos: ArrayList<BitcoinTransaction.UTXO>,
walletId: String,
feeProviderWalletId: String
): TxSignResult {
val signUsdtCollectPo = SignUsdtCollectPo()
signUsdtCollectPo.feeProviderUtxos = feeProviderUtxos
signUsdtCollectPo.fee = fee
signUsdtCollectPo.feeProviderWalletId = feeProviderWalletId
signUsdtCollectPo.walletId = walletId
signUsdtCollectPo.toAddress = toAddress
signUsdtCollectPo.amount = amount
signUsdtCollectPo.utxos = utxos
return exchange(
"${getHsmUrl()}${HsmReuqestType.SIGN_USDT_COLLECT_TRANSACTION}",
HttpMethod.POST,
signUsdtCollectPo,
TxSignResult::class.java
)
}


fun checkWallet(walletCode: String): String {

return exchange(
"${getHsmUrl()}${HsmReuqestType.CHECK_WALLET}/$walletCode",
HttpMethod.GET,
null,
String::class.java
)
}

fun exportWallet(walletCode: String, type: Int): String {
return exchange(
return hsmXService.deriveWallets(chainTypes)
return hsmXService.signUsdtTransaction(signUsdtPo)
fun signBtcTransaction(amount: BigDecimal, fee: BigDecimal, toAddress: String, utxos: ArrayList<BitcoinTransaction.UTXO>, walletId: String): TxSignResult {
return hsmXService.signBitcoinTransaction(signBitcoinPo)
fun signEthtransaction(nonce: Int, amount: BigDecimal, gasPrice: BigDecimal, gasLimit: Long, toAddress: String, walletId: String, data: String?): TxSignResult {
return hsmXService.signEthereumTransaction(signEthereumPo)
fun signUsdtCollectTransaction(toAddress: String, amount: BigDecimal, fee: BigDecimal, utxos: ArrayList<BitcoinTransaction.UTXO>, feeProviderUtxos: ArrayList<BitcoinTransaction.UTXO>, walletId: String, feeProviderWalletId: String): TxSignResult {
return hsmXService.signUsdtCollectTransaction(signUsdtCollectPo)
fun checkWallet(walletCode: String): String = hsmXService.getAllWallets().firstOrNull { it.walletCode == walletCode }?.address ?: ""
fun exportWallet(walletCode: String, type: Int): String = hsmXService.exportWallet(walletCode, type)
fun removeUselessWallet(map: Map<String, String>) { hsmXService.removeUselessWallet(map) }
fun importWallet(importWalletPo: ImportWalletPo): AddressVo = hsmXService.importWallet(importWalletPo)
lateinit var hsmXService: com.wallet.hsm.xservice.HsmXService
"${getHsmUrl()}${HsmReuqestType.EXPORT_WALLET}/$walletCode/$type",
HttpMethod.GET,
null,
Expand Down
3 changes: 2 additions & 1 deletion wallet-webapi/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mainClassName = "com.wallet.WebApiApplicationKt"

dependencies {
implementation project(":wallet-common")
implementation project(":wallet-hsm")
}

jib {
Expand All @@ -19,7 +20,7 @@ jib {
}
container {
mainClass = 'com.wallet.WebApiApplicationKt'
ports = ['10001']
ports = ['8080']
jvmFlags = ['-Xms256m', '-Xmx512m', '-Djava.security.egd=file:/dev/./urandom']
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.wallet.webapi.controller

import com.wallet.biz.domain.dict.TokenResponse
import com.wallet.biz.service.ConfigService
import com.wallet.biz.dict.SysConfigKey
import com.wallet.biz.xservice.AdminXService
import com.wallet.entity.domain.*
import io.swagger.v3.oas.annotations.Operation
Expand All @@ -10,15 +12,82 @@ import jakarta.servlet.http.HttpServletRequest
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@Tag(name = "Admin API", description = "管理后台接口")
@RequestMapping("admin")
class AdminController {
private val auditLogs = mutableListOf<Map<String, String>>()

@GetMapping("get_user")
@GetMapping("config/rpc")
@Operation(summary = "RPC配置")
fun getRpcConfig(): TokenResponse<Map<String, String>> {
val keys = listOf(SysConfigKey.ETH_RPC_URL, SysConfigKey.OMNI_RPC_URL, SysConfigKey.BCH_RPC_URL, SysConfigKey.TRX_API_URL)
return TokenResponse(keys.associate { it.name to maskSensitive(it.name, findConfig(it.name)) })
}

@PutMapping("config/rpc")
@Operation(summary = "更新RPC配置")
fun putRpcConfig(key: String, value: String): TokenResponse<Any> {
saveConfigByKey(key, value)
audit("UPDATE_RPC_CONFIG", key, value)
return TokenResponse()
}

@GetMapping("config/scheduler")
@Operation(summary = "调度配置")
fun getSchedulerConfig(): TokenResponse<Map<String, String>> {
val keys = SysConfigKey.values().filter { it.name.startsWith("SCHEDULER_") }
return TokenResponse(keys.associate { it.name to findConfig(it.name) })
}

@PutMapping("config/scheduler")
@Operation(summary = "更新调度配置")
fun putSchedulerConfig(key: String, value: String): TokenResponse<Any> {
saveConfigByKey(key, value)
audit("UPDATE_SCHEDULER_CONFIG", key, value)
return TokenResponse()
}



@GetMapping("config/chains")
@Operation(summary = "链配置")
fun getChainConfig(): TokenResponse<Map<String, String>> {
val keys = listOf(SysConfigKey.ETH_SCAN_BACK, SysConfigKey.BTC_SCAN_BACK, SysConfigKey.TRX_SCAN_BACK)
return TokenResponse(keys.associate { it.name to findConfig(it.name) })
}

@PutMapping("config/chains")
@Operation(summary = "更新链配置")
fun putChainConfig(key: String, value: String): TokenResponse<Any> {
saveConfigByKey(key, value)
audit("UPDATE_CHAIN_CONFIG", key, value)
return TokenResponse()
}

@GetMapping("config/security")
@Operation(summary = "安全配置")
fun getSecurityConfig(): TokenResponse<Map<String, String>> {
val keys = listOf("SECURITY_ALLOW_EXPORT_PRIVATE_KEY", "SECURITY_REQUIRE_2FA_ON_EXPORT", "SECURITY_MASK_SENSITIVE_FIELDS")
return TokenResponse(keys.associateWith { maskSensitive(it, findConfig(it)) })
}

@PutMapping("config/security")
@Operation(summary = "更新安全配置")
fun putSecurityConfig(key: String, value: String): TokenResponse<Any> {
saveConfigByKey(key, value)
audit("UPDATE_SECURITY_CONFIG", key, value)
return TokenResponse()
}

@GetMapping("config/audit-logs")
@Operation(summary = "审计日志")
fun getAuditLogs(): TokenResponse<List<Map<String, String>>> = TokenResponse(auditLogs.takeLast(200).reversed())
@GetMapping("get_user")
@Operation(summary = "获取用户")
fun getUser(): TokenResponse<User> {
val user = request.getAttribute("user") as User
Expand Down Expand Up @@ -177,4 +246,26 @@ class AdminController {

@Resource
lateinit var request: HttpServletRequest

@Autowired
lateinit var configService: ConfigService

private fun findConfig(key: String): String = configService.findAll().firstOrNull { it.configKey == key }?.configValue ?: ""

private fun saveConfigByKey(key: String, value: String) {
val item = configService.findAll().firstOrNull { it.configKey == key } ?: Config().also { it.configKey = key }
if (value.isBlank()) return
item.configValue = value
configService.save(item)
}

private fun audit(action: String, key: String, value: String) {
auditLogs.add(mapOf("action" to action, "key" to key, "value" to maskSensitive(key, value), "operator" to ((request.getHeader("X-Admin-User") ?: "system")), "time" to java.time.Instant.now().toString()))
}

private fun maskSensitive(key: String, value: String): String {
if (!key.contains("PASSWORD") && !key.contains("KEY")) return value
if (value.length <= 8) return "****"
return value.take(4) + "****" + value.takeLast(4)
}
}
Loading
Loading