Skip to content

Commit

Permalink
Merge branch 'master' into feature/update-outdated-packages
Browse files Browse the repository at this point in the history
  • Loading branch information
martintatum authored Dec 19, 2024
2 parents 5d674db + 1d14a97 commit 4cd3717
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 48 deletions.
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ When KMS runs in [daemon mode](#run-kms-in-daemon-mode), use the following comma
}
}
```
* `checkconfig` shows environment variables for Tatum KMS (for debugging).
* `checkconfig`(for debugging) shows environment variables for Tatum KMS.
```
bash:$ tatum-kms checkconfig
Expand All @@ -385,6 +385,40 @@ When KMS runs in [daemon mode](#run-kms-in-daemon-mode), use the following comma
Env file : .env
TATUM_API_KEY : d2eb5c******************************
...
```
* `report`(for debugging) shows report of system and requested wallets (+ warnings if they were found)
```
bash:$ tatum-kms report e3015fc0-2112-4c8a-b8bf-353b86f63ba5,11115fc0-2112-4c8a-b8bf-353b86f63111
{
"system": {
"kmsVersion": "7.0.6",
"nodeVersion": "v18.18.2",
"store": {
"type": "LOCAL",
"exists": true
}
},
"wallets": {
"e3015fc0-2112-4c8a-b8bf-353b86f63ba5": {
"type": "PRIVATE_KEY",
"chain": "BTC",
"testnet": true
},
"11115fc0-2112-4c8a-b8bf-353b86f63111": {
"type": "MNEMONIC",
"chain": "ETH",
"testnet": true,
"warnings": [
"No xpub found"
]
}
},
"apiKey": "t-6111***************************************222222",
"warnings": [
"Wallets file was is not accessible"
]
}
```
## Common issues
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tatumio/tatum-kms",
"version": "7.0.6",
"version": "7.0.8",
"description": "Tatum KMS - Key Management System for Tatum-powered apps.",
"main": "dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
18 changes: 16 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getQuestion,
getWallet,
removeWallet,
report,
setTatumKey,
storePrivateKey,
storeWallet,
Expand All @@ -23,6 +24,7 @@ import HttpAgent from 'agentkeepalive'
import { existsSync } from 'fs'
import * as process from 'process'
import { homedir } from 'os'
import { utils } from './utils'

dotenv.config()

Expand All @@ -47,21 +49,25 @@ const axiosInstance = axios.create()

const optionsConst = `
Usage
$ tatum-kms command
$ tatum-kms <command>
Commands
daemon Run as a daemon, which periodically checks for a new transactions to sign.
generatewallet <chain> Generate wallet for a specific blockchain and echo it to the output.
generatemanagedwallet <chain> Generate wallet for a specific blockchain and add it to the managed wallets.
storemanagedwallet <chain> Store mnemonic-based wallet for a specific blockchain and add it to the managed wallets.
storemanagedprivatekey <chain> Store private key of a specific blockchain and add it to the managed wallets.
generatemanagedprivatekeybatch <chain> <cnt> generate and store "cnt" number of private keys for a specific blockchain. This operation is usefull, if you wanna pregenerate bigger amount of managed private keys for later use.
generatemanagedprivatekeybatch <chain> <cnt> Generate and store "cnt" number of private keys for a specific blockchain. This operation is usefull, if you wanna pregenerate bigger amount of managed private keys for later use.
getprivatekey <signatureId> <i> Obtain managed wallet from wallet store and generate private key for given derivation index.
getaddress <signatureId> <i> Obtain managed wallet from wallet store and generate address for given derivation index.
getmanagedwallet <signatureId> Obtain managed wallet / private key from wallet store.
removewallet <signatureId> Remove managed wallet from wallet store.
export Export all managed wallets.
Debugging
report Shows report of system and requested wallets (+ warnings if they were found)
checkconfig Shows environment variables for Tatum KMS.
Options
--apiKey Tatum API Key to communicate with Tatum API. Daemon mode only.
--testnet Indicates testnet version of blockchain. Mainnet by default.
Expand Down Expand Up @@ -225,6 +231,14 @@ const startup = async () => {
case 'checkconfig':
checkConfig(getPasswordType(flags), envFilePath, flags.path as string)
break
case 'report':
await report(
utils.csvToArray(command[1]),
getPasswordType(),
await getPassword(getPasswordType(), axiosInstance),
flags.path,
)
break
default:
console.error('Unsupported command. Use tatum-kms --help for details.')
process.exit(-1)
Expand Down
41 changes: 40 additions & 1 deletion src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ export interface Signature {

export interface Wallet {
mnemonic: string
xpub: string
testnet: boolean
privateKey: string
secret: string
chain: Currency
}

export interface WalletsValidationOptions {
Expand All @@ -29,4 +32,40 @@ export interface StoreWalletValue {
xpub?: string
}

export type ExternalUrlMethod = 'GET' | 'POST';
export type ExternalUrlMethod = 'GET' | 'POST'

export type Report = {
system: {
kmsVersion: string
nodeVersion: string
store: {
type: string
exists: boolean
}
}
wallets: Record<string, ReportWallet>
apiKey: string
warnings?: string[]
}

export type ReportWallet = {
type: WalletType
chain: Currency
testnet: boolean
warnings?: string[]
}

export enum WalletType {
MNEMONIC = 'MNEMONIC',
PRIVATE_KEY = 'PRIVATE_KEY',
SECRET = 'SECRET',
OTHER = 'OTHER',
}

export enum WalletStoreType {
LOCAL = 'LOCAL',
VGS = 'VGS',
AZURE = 'AZURE',
AWS = 'AWS',
NA = 'N/A',
}
165 changes: 128 additions & 37 deletions src/management.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,21 @@ import { dirname } from 'path'
import { question } from 'readline-sync'
import { v4 as uuid } from 'uuid'
import { Config, ConfigOption } from './config'
import { PasswordType, Signature, StoreWalletValue, WalletsValidationOptions } from './interfaces'
import {
PasswordType,
Report,
ReportWallet,
Signature,
StoreWalletValue,
Wallet,
WalletStoreType,
WalletsValidationOptions,
WalletType,
} from './interfaces'
import { utils } from './utils'
import semver from 'semver'

import { version } from '../package.json'

const { AES } = CryptoJS

Expand Down Expand Up @@ -398,59 +412,128 @@ export const removeWallet = async (id: string, pwd: string, path?: string) => {
writeFileSync(pathToWallet, AES.encrypt(JSON.stringify(wallet), pwd).toString())
}

function parseWalletStoreName(pwdType: PasswordType): string {
function parseWalletStoreName(pwdType: PasswordType): WalletStoreType {
if (pwdType === PasswordType.CMD_LINE) {
return 'LOCAL'
return WalletStoreType.LOCAL
} else if (pwdType === PasswordType.VGS) {
return 'VGS'
return WalletStoreType.VGS
} else if (pwdType === PasswordType.AZURE) {
return 'AZURE'
return WalletStoreType.AZURE
} else if (pwdType === PasswordType.AWS) {
return 'AWS'
}
return 'N/A'
}

function hidePassword(password: string | undefined, showSymbols = 6): string {
if (!password) {
return ''
}
if (password.length <= showSymbols) {
return '*'.repeat(password.length)
return WalletStoreType.AWS
}
return password.slice(0, showSymbols) + '*'.repeat(password.length - showSymbols)
}

function secretValue(secretValue: string | undefined): string {
if (!secretValue) {
return 'N/A'
}
return hidePassword(secretValue)
return WalletStoreType.NA
}

export const checkConfig = (pwdType: PasswordType, envFile?: string, path?: string) => {
const pathToWallet = path || homedir() + '/.tatumrc/wallet.dat'
console.log(`Version : ${process.env.npm_package_version ?? 'N/A'}`)
console.log(`Version : ${getKmsVersion()}`)
console.log(`Wallet file path : ${pathToWallet}`)
console.log(`Wallet exists : ${existsSync(pathToWallet)}`)
console.log(`Wallet store type : ${parseWalletStoreName(pwdType)}`)
console.log(`Environment vars file : ${envFile ?? 'N/A'}`)
console.log(`TATUM_API_KEY : ${secretValue(process.env.TATUM_API_KEY)}`)
console.log(`TATUM_KMS_PASSWORD : ${secretValue(process.env.TATUM_KMS_PASSWORD)}`)
console.log(`TATUM_KMS_VGS_ALIAS : ${secretValue(process.env.TATUM_KMS_VGS_ALIAS)}`)
console.log(`TATUM_KMS_VGS_USERNAME : ${secretValue(process.env.TATUM_KMS_VGS_USERNAME)}`)
console.log(`TATUM_KMS_VGS_PASSWORD : ${secretValue(process.env.TATUM_KMS_VGS_PASSWORD)}`)
console.log(`TATUM_KMS_AZURE_SECRETVERSION : ${secretValue(process.env.TATUM_KMS_AZURE_SECRETVERSION)}`)
console.log(`TATUM_KMS_AZURE_SECRETNAME : ${secretValue(process.env.TATUM_KMS_AZURE_SECRETNAME)}`)
console.log(`TATUM_KMS_AZURE_VAULTURL : ${secretValue(process.env.TATUM_KMS_AZURE_VAULTURL)}`)
console.log(`TATUM_API_KEY : ${utils.hideApiKey(process.env.TATUM_API_KEY)}`)
console.log(`TATUM_KMS_PASSWORD : ${utils.hidePassword(process.env.TATUM_KMS_PASSWORD)}`)
console.log(`TATUM_KMS_VGS_ALIAS : ${utils.hidePassword(process.env.TATUM_KMS_VGS_ALIAS)}`)
console.log(`TATUM_KMS_VGS_USERNAME : ${utils.hidePassword(process.env.TATUM_KMS_VGS_USERNAME)}`)
console.log(`TATUM_KMS_VGS_PASSWORD : ${utils.hidePassword(process.env.TATUM_KMS_VGS_PASSWORD)}`)
console.log(`TATUM_KMS_AZURE_SECRETVERSION : ${utils.hidePassword(process.env.TATUM_KMS_AZURE_SECRETVERSION)}`)
console.log(`TATUM_KMS_AZURE_SECRETNAME : ${utils.hidePassword(process.env.TATUM_KMS_AZURE_SECRETNAME)}`)
console.log(`TATUM_KMS_AZURE_VAULTURL : ${utils.hidePassword(process.env.TATUM_KMS_AZURE_VAULTURL)}`)
console.log(`TATUM_KMS_AWS_REGION : ${process.env.TATUM_KMS_AWS_REGION ?? 'N/A'}`)
console.log(`TATUM_KMS_AWS_ACCESS_KEY_ID : ${secretValue(process.env.TATUM_KMS_AWS_ACCESS_KEY_ID)}`)
console.log(`TATUM_KMS_AWS_SECRET_ACCESS_KEY : ${secretValue(process.env.TATUM_KMS_AWS_SECRET_ACCESS_KEY)}`)
console.log(`TATUM_KMS_AWS_SECRET_NAME : ${secretValue(process.env.TATUM_KMS_AWS_SECRET_NAME)}`)
console.log(`TATUM_KMS_AWS_SECRET_KEY : ${secretValue(process.env.TATUM_KMS_AWS_SECRET_KEY)}`)
console.log(`TATUM_KMS_AWS_ACCESS_KEY_ID : ${utils.hidePassword(process.env.TATUM_KMS_AWS_ACCESS_KEY_ID)}`)
console.log(`TATUM_KMS_AWS_SECRET_ACCESS_KEY : ${utils.hidePassword(process.env.TATUM_KMS_AWS_SECRET_ACCESS_KEY)}`)
console.log(`TATUM_KMS_AWS_SECRET_NAME : ${utils.hidePassword(process.env.TATUM_KMS_AWS_SECRET_NAME)}`)
console.log(`TATUM_KMS_AWS_SECRET_KEY : ${utils.hidePassword(process.env.TATUM_KMS_AWS_SECRET_KEY)}`)
console.log(`TATUM_KMS_DEBUG_MODE : ${process.env.TATUM_KMS_DEBUG_MODE ?? 'N/A'}`)
}

export const report = async (signatureIds: string[], passwordType: PasswordType, pwd: string, path?: string) => {
const systemWarnings: string[] = []
const walletReports: Record<string, ReportWallet> = {}
for (const signatureId of signatureIds) {
const wallet: Wallet = await getWallet(signatureId, pwd, path, false)
if (!wallet) {
systemWarnings.push(`No wallet found for signatureId: ${signatureId}`)
continue
}
if (!_.isObject(wallet)) {
systemWarnings.push(`Wallet for signatureId: ${signatureId} is not an object. Its type is: ${typeof wallet}`)
continue
}

const warnings: string[] = []
const type: WalletType = validateWallet(wallet, warnings)

walletReports[signatureId] = {
type: type,
chain: wallet.chain,
testnet: wallet.testnet,
warnings: warnings && warnings.length > 0 ? warnings : undefined,
}
}
const nodeVersion = validateNodeVersion(systemWarnings)

const report: Report = {
system: {
kmsVersion: getKmsVersion(),
nodeVersion: nodeVersion,
store: {
type: parseWalletStoreName(passwordType),
exists: existsSync(getPathToWallet(path)),
},
},
wallets: walletReports,
apiKey: utils.hideApiKey(process.env.TATUM_API_KEY),
warnings: systemWarnings && systemWarnings.length > 0 ? systemWarnings : undefined,
}

console.log(JSON.stringify(report, null, 2))
}

const validateWallet = (wallet: Wallet, warnings: string[]) => {
if (wallet.mnemonic) {
validateStringField(warnings, 'chain', wallet.chain)
validateStringField(warnings, 'mnemonic', wallet.mnemonic)
validateStringField(warnings, 'xpub', wallet.xpub)
validateBooleanField(warnings, 'testnet', wallet.testnet)
return WalletType.MNEMONIC
} else if (wallet.privateKey) {
validateStringField(warnings, 'chain', wallet.chain)
validateStringField(warnings, 'privateKey', wallet.privateKey)
validateBooleanField(warnings, 'testnet', wallet.testnet)
return WalletType.PRIVATE_KEY
} else if (wallet.secret) {
validateStringField(warnings, 'chain', wallet.chain)
validateStringField(warnings, 'secret', wallet.secret)
validateBooleanField(warnings, 'testnet', wallet.testnet)
return WalletType.SECRET
} else {
warnings.push('Wallet type is not recognized. Mnemonic, privateKey or secret are absent')
return WalletType.OTHER
}
}

const validateNodeVersion = (systemWarnings: string[]) => {
const nodeVersion = process.version
if (semver.lt(nodeVersion, '18.0.0')) {
systemWarnings.push(`Node version is lower than v18.x.x. Current version is: ${nodeVersion}`)
}
return nodeVersion
}

const validateStringField = (warnings: string[], fieldName: string, value: unknown) => {
if (!_.isString(value)) {
warnings.push(`Field '${fieldName}' is not string. Its type is: ${typeof value}`)
}
}

const validateBooleanField = (warnings: string[], fieldName: string, value: unknown) => {
if (!_.isBoolean(value)) {
warnings.push(`Field '${fieldName}' is not boolean. Its type is: ${typeof value}`)
}
}

export const setTatumKey = (apiKey: string) => {
if (apiKey) {
process.env.TATUM_API_KEY = apiKey
Expand All @@ -465,3 +548,11 @@ export const getQuestion = (q: string, e?: string) => {
hideEchoBack: true,
})
}

const getKmsVersion = (): string => {
return version || 'N/A'
}

const getPathToWallet = (path?: string) => {
return path || homedir() + '/.tatumrc/wallet.dat'
}
Loading

0 comments on commit 4cd3717

Please sign in to comment.