pre unlocked
This commit is contained in:
parent
b1af2997b0
commit
32dbd20a76
3 changed files with 43 additions and 17 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
import { InitWalletRequest } from "../../../proto/lnd/walletunlocker";
|
import { InitWalletRequest } from "../../../proto/lnd/walletunlocker";
|
||||||
|
|
||||||
|
|
||||||
export const InitWalletReq = (secret: Buffer, cipherSeedMnemonic: string[]): InitWalletRequest => ({
|
export const InitWalletReq = (walletPw: Buffer, cipherSeedMnemonic: string[]): InitWalletRequest => ({
|
||||||
aezeedPassphrase: Buffer.alloc(0),
|
aezeedPassphrase: Buffer.alloc(0),
|
||||||
walletPassword: secret,
|
walletPassword: walletPw,
|
||||||
cipherSeedMnemonic,
|
cipherSeedMnemonic,
|
||||||
extendedMasterKey: "",
|
extendedMasterKey: "",
|
||||||
extendedMasterKeyBirthdayTimestamp: 0n,
|
extendedMasterKeyBirthdayTimestamp: 0n,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ export type MainSettings = {
|
||||||
watchDogSettings: WatchdogSettings,
|
watchDogSettings: WatchdogSettings,
|
||||||
liquiditySettings: LiquiditySettings,
|
liquiditySettings: LiquiditySettings,
|
||||||
jwtSecret: string
|
jwtSecret: string
|
||||||
|
walletPasswordPath: string
|
||||||
walletSecretPath: string
|
walletSecretPath: string
|
||||||
incomingTxFee: number
|
incomingTxFee: number
|
||||||
outgoingTxFee: number
|
outgoingTxFee: number
|
||||||
|
|
@ -45,6 +46,7 @@ export const LoadMainSettingsFromEnv = (): MainSettings => {
|
||||||
liquiditySettings: LoadLiquiditySettingsFromEnv(),
|
liquiditySettings: LoadLiquiditySettingsFromEnv(),
|
||||||
jwtSecret: loadJwtSecret(storageSettings.dataDir),
|
jwtSecret: loadJwtSecret(storageSettings.dataDir),
|
||||||
walletSecretPath: process.env.WALLET_SECRET_PATH || getDataPath(storageSettings.dataDir, ".wallet_secret"),
|
walletSecretPath: process.env.WALLET_SECRET_PATH || getDataPath(storageSettings.dataDir, ".wallet_secret"),
|
||||||
|
walletPasswordPath: process.env.WALLET_PASSWORD_PATH || getDataPath(storageSettings.dataDir, ".wallet_password"),
|
||||||
incomingTxFee: EnvCanBeInteger("INCOMING_CHAIN_FEE_ROOT_BPS", 0) / 10000,
|
incomingTxFee: EnvCanBeInteger("INCOMING_CHAIN_FEE_ROOT_BPS", 0) / 10000,
|
||||||
outgoingTxFee: EnvCanBeInteger("OUTGOING_CHAIN_FEE_ROOT_BPS", 60) / 10000,
|
outgoingTxFee: EnvCanBeInteger("OUTGOING_CHAIN_FEE_ROOT_BPS", 60) / 10000,
|
||||||
incomingAppInvoiceFee: EnvCanBeInteger("INCOMING_INVOICE_FEE_ROOT_BPS", 0) / 10000,
|
incomingAppInvoiceFee: EnvCanBeInteger("INCOMING_INVOICE_FEE_ROOT_BPS", 0) / 10000,
|
||||||
|
|
|
||||||
|
|
@ -55,12 +55,9 @@ export class Unlocker {
|
||||||
throw new Error("failed to get lnd info for reason: " + info.failure)
|
throw new Error("failed to get lnd info for reason: " + info.failure)
|
||||||
}
|
}
|
||||||
this.log("wallet is locked, unlocking...")
|
this.log("wallet is locked, unlocking...")
|
||||||
const secret = this.GetWalletSecret(false)
|
|
||||||
if (!secret) {
|
|
||||||
throw new Error("wallet secret not found to unlock wallet")
|
|
||||||
}
|
|
||||||
const unlocker = this.GetUnlockerClient(lndCert)
|
const unlocker = this.GetUnlockerClient(lndCert)
|
||||||
await unlocker.unlockWallet({ walletPassword: Buffer.from(secret, 'hex'), recoveryWindow: 0, statelessInit: false, channelBackups: undefined }, DeadLineMetadata())
|
const walletPassword = this.GetWalletPassword()
|
||||||
|
await unlocker.unlockWallet({ walletPassword, recoveryWindow: 0, statelessInit: false, channelBackups: undefined }, DeadLineMetadata())
|
||||||
const infoAfter = await this.GetLndInfo(ln)
|
const infoAfter = await this.GetLndInfo(ln)
|
||||||
if (!infoAfter.ok) {
|
if (!infoAfter.ok) {
|
||||||
throw new Error("failed to init lnd wallet " + infoAfter.failure)
|
throw new Error("failed to init lnd wallet " + infoAfter.failure)
|
||||||
|
|
@ -80,8 +77,9 @@ export class Unlocker {
|
||||||
console.log(seedRes.response.cipherSeedMnemonic)
|
console.log(seedRes.response.cipherSeedMnemonic)
|
||||||
console.log(seedRes.response.encipheredSeed)
|
console.log(seedRes.response.encipheredSeed)
|
||||||
this.log("seed created, encrypting and saving...")
|
this.log("seed created, encrypting and saving...")
|
||||||
const { encryptedData, secret } = this.EncryptWalletSeed(seedRes.response.cipherSeedMnemonic)
|
const { encryptedData } = this.EncryptWalletSeed(seedRes.response.cipherSeedMnemonic)
|
||||||
const req = InitWalletReq(secret, seedRes.response.cipherSeedMnemonic)
|
const walletPw = this.GetWalletPassword()
|
||||||
|
const req = InitWalletReq(walletPw, seedRes.response.cipherSeedMnemonic)
|
||||||
const initRes = await unlocker.initWallet(req, DeadLineMetadata(60 * 1000))
|
const initRes = await unlocker.initWallet(req, DeadLineMetadata(60 * 1000))
|
||||||
const adminMacaroon = Buffer.from(initRes.response.adminMacaroon).toString('hex')
|
const adminMacaroon = Buffer.from(initRes.response.adminMacaroon).toString('hex')
|
||||||
const ln = this.GetLightningClient(lndCert, adminMacaroon)
|
const ln = this.GetLightningClient(lndCert, adminMacaroon)
|
||||||
|
|
@ -115,7 +113,7 @@ export class Unlocker {
|
||||||
}
|
}
|
||||||
|
|
||||||
EncryptWalletSeed = (seed: string[]) => {
|
EncryptWalletSeed = (seed: string[]) => {
|
||||||
return this.encrypt(seed.join('+'))
|
return this.encrypt(seed.join('+'), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
DecryptWalletSeed = (data: { iv: string, encrypted: string }) => {
|
DecryptWalletSeed = (data: { iv: string, encrypted: string }) => {
|
||||||
|
|
@ -129,8 +127,11 @@ export class Unlocker {
|
||||||
return Buffer.from(this.decrypt(data), 'hex')
|
return Buffer.from(this.decrypt(data), 'hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
encrypt = (text: string) => {
|
encrypt = (text: string, must = false) => {
|
||||||
const sec = this.GetWalletSecret(true)
|
const sec = this.GetWalletSecret(must)
|
||||||
|
if (!sec) {
|
||||||
|
throw new Error("wallet secret not found to encrypt")
|
||||||
|
}
|
||||||
const secret = Buffer.from(sec, 'hex')
|
const secret = Buffer.from(sec, 'hex')
|
||||||
const iv = crypto.randomBytes(16)
|
const iv = crypto.randomBytes(16)
|
||||||
const cipher = crypto.createCipheriv('aes-256-cbc', secret, iv)
|
const cipher = crypto.createCipheriv('aes-256-cbc', secret, iv)
|
||||||
|
|
@ -138,13 +139,13 @@ export class Unlocker {
|
||||||
const cyData = cipher.update(rawData)
|
const cyData = cipher.update(rawData)
|
||||||
const encrypted = Buffer.concat([cyData, cipher.final()])
|
const encrypted = Buffer.concat([cyData, cipher.final()])
|
||||||
const encryptedData = { iv: iv.toString('hex'), encrypted: encrypted.toString('hex') }
|
const encryptedData = { iv: iv.toString('hex'), encrypted: encrypted.toString('hex') }
|
||||||
return { encryptedData, secret }
|
return { encryptedData }
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt = (data: { iv: string, encrypted: string }) => {
|
decrypt = (data: { iv: string, encrypted: string }) => {
|
||||||
const sec = this.GetWalletSecret(false)
|
const sec = this.GetWalletSecret(false)
|
||||||
if (!sec) {
|
if (!sec) {
|
||||||
throw new Error("wallet secret not found to decrypt seed")
|
throw new Error("wallet secret not found to decrypt")
|
||||||
}
|
}
|
||||||
const secret = Buffer.from(sec, 'hex')
|
const secret = Buffer.from(sec, 'hex')
|
||||||
const iv = Buffer.from(data.iv, 'hex')
|
const iv = Buffer.from(data.iv, 'hex')
|
||||||
|
|
@ -164,20 +165,43 @@ export class Unlocker {
|
||||||
this.log("the wallet secret file was not found")
|
this.log("the wallet secret file was not found")
|
||||||
}
|
}
|
||||||
if (secret === "" && create) {
|
if (secret === "" && create) {
|
||||||
|
this.log("creating wallet secret file")
|
||||||
secret = crypto.randomBytes(32).toString('hex')
|
secret = crypto.randomBytes(32).toString('hex')
|
||||||
fs.writeFileSync(path, secret)
|
fs.writeFileSync(path, secret)
|
||||||
}
|
}
|
||||||
return secret
|
return secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetWalletPassword = () => {
|
||||||
|
const path = this.settings.walletPasswordPath
|
||||||
|
let password = Buffer.alloc(0)
|
||||||
|
try {
|
||||||
|
password = fs.readFileSync(path)
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
if (password.length === 0) {
|
||||||
|
this.log("no wallet password configured, using wallet secret")
|
||||||
|
const secret = this.GetWalletSecret(false)
|
||||||
|
if (secret === "") {
|
||||||
|
throw new Error("no usable password found")
|
||||||
|
}
|
||||||
|
password = Buffer.from(secret, 'hex')
|
||||||
|
}
|
||||||
|
return password
|
||||||
|
}
|
||||||
|
|
||||||
subscribeToBackups = async (ln: LightningClient, pub: string) => {
|
subscribeToBackups = async (ln: LightningClient, pub: string) => {
|
||||||
this.log("subscribing to channel backups for: ", pub)
|
this.log("subscribing to channel backups for: ", pub)
|
||||||
const stream = ln.subscribeChannelBackups({}, { abort: this.abortController.signal })
|
const stream = ln.subscribeChannelBackups({}, { abort: this.abortController.signal })
|
||||||
stream.responses.onMessage((msg) => {
|
stream.responses.onMessage(async (msg) => {
|
||||||
if (msg.multiChanBackup) {
|
if (msg.multiChanBackup) {
|
||||||
this.log("received backup, saving")
|
this.log("received backup, saving")
|
||||||
|
try {
|
||||||
const { encryptedData } = this.EncryptBackup(Buffer.from(msg.multiChanBackup.multiChanBackup))
|
const { encryptedData } = this.EncryptBackup(Buffer.from(msg.multiChanBackup.multiChanBackup))
|
||||||
this.storage.liquidityStorage.SaveNodeBackup(pub, JSON.stringify(encryptedData))
|
await this.storage.liquidityStorage.SaveNodeBackup(pub, JSON.stringify(encryptedData))
|
||||||
|
} catch (err: any) {
|
||||||
|
this.log("failed to save backup", err.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue