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: implement tools for channel backup #18

Open
wants to merge 1 commit 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
1 change: 1 addition & 0 deletions NRustLightning.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RPC/@EntryIndexedValue">RPC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQ/@EntryIndexedValue">SQ</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Aezeed/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=allowinsecure/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BITCOIND/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=broadcastable/@EntryIndexedValue">True</s:Boolean>
Expand Down
22 changes: 22 additions & 0 deletions src/NRustLightning.CLI/ChannelTools/ChanTools.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.CommandLine;

namespace NRustLightning.CLI.ChannelTools
{
public class ChanTools
{
/// <summary>
/// Get common options for `chantools` subcommand.
/// </summary>
/// <returns></returns>
public Option[] GetOptions() =>
new Option[]
{
new Option(""),
};

public Command ChanBackup()
{
var opts =
}
}
}
51 changes: 51 additions & 0 deletions src/NRustLightning.CLI/CommandLineUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Text;
using System.Text.RegularExpressions;
using DotNetLightning.Crypto;
using Microsoft.FSharp.Core;
using NBitcoin;
using NRustLightning.Infrastructure.Utils;

namespace NRustLightning.CLI
{
public static class CommandLineUtils
{
private static Regex NumberDotsRegex = new Regex("[\\d.\\-\\n\\r\\t]*");
private static Regex MultipleSpaces = new Regex(" [ ]+");

public static bool TryReadAezeedFromTerminal(out ExtKey? rootKey)
{
rootKey = null;
string? mnemonicStr = null;
while (string.IsNullOrEmpty(mnemonicStr))
{
Console.WriteLine("Input your 24-word mnemonic separated by spaces: ");
mnemonicStr = Console.ReadLine()?.Trim().ToLower();
}

// To allow the tool to also accept the copy/pasted version of the backup text (which contains numbers and
// dts and multiple spaces), we do some more cleanup with regex.
mnemonicStr =
NumberDotsRegex.Replace(mnemonicStr, "");
mnemonicStr = MultipleSpaces.Replace(mnemonicStr, " ").Trim();

var mnemonics = new Mnemonic(mnemonicStr);
Console.WriteLine();
if (mnemonics.Words.Length != 24)
{
Console.WriteLine($"wrong cipher seed. mnemonic length: got {mnemonics.Words.Length}, expecting {24} words");
return false;
}
var seedPassphrase = CliUtils.GetNewSeedPass();
var r = mnemonics.ToCipherSeed(Encoding.UTF8.GetBytes(seedPassphrase), null);
if (r.IsError)
{
Console.WriteLine(r.ErrorValue);
return false;
}
var cipherSeed = r.ResultValue;
rootKey = new ExtKey(cipherSeed.Entropy.AsSpan());
return true;
}
}
}
37 changes: 0 additions & 37 deletions src/NRustLightning.Infrastructure/Configuration/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ public class Config

private string? _seedFromConfig;

private string? _pin;

public NRustLightningNetworkProvider NetworkProvider { get; set; }

Expand Down Expand Up @@ -139,7 +138,6 @@ public Config LoadArgs(IConfiguration config, ILogger? logger)

DBCacheMB = config.GetOrDefault("dbcache", Constants.DefaultDBCacheMB);
_seedFromConfig = config.GetOrDefault("seed", string.Empty);
_pin = config.GetOrDefault("pin", string.Empty);
SeedFilePath = Path.Join(DataDir, "node_secret");
return this;
}
Expand All @@ -160,40 +158,5 @@ public string GetSeedInConfig()
return _seedFromConfig;
}

public string Pin => _pin;

public string GetNewPin()
{
string pin = _pin;
if (!string.IsNullOrEmpty(pin)) return pin;

Console.WriteLine("========================================================================");
Console.WriteLine("Please enter the pin code to secure your seed on disk ");
Console.WriteLine("It is recommended to be longer than 10 characters to be cryptographically secure");
Console.WriteLine("Please do not forget this pin code. You will need it when restarting the server");
Console.WriteLine("========================================================================");
while (true)
{
Console.WriteLine("Please enter your pin code: ");
var pin1 = Console.ReadLine();
Console.WriteLine("Please enter again:");
var pin2 = Console.ReadLine();
if (pin1 == pin2 && !string.IsNullOrEmpty(pin1))
{
pin = pin1;
break;
}
else if (pin1 == pin2)
{
Console.WriteLine("You cannot specify empty pin code");
}
else
{
Console.WriteLine("pin code mismatch! try again");
}
}

return pin;
}
}
}
87 changes: 87 additions & 0 deletions src/NRustLightning.Infrastructure/Utils/CliUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using DotNetLightning.Crypto;
using NRustLightning.Infrastructure.Configuration;

namespace NRustLightning.Infrastructure.Utils
{
public static class CliUtils
{
public static bool AskUserYesOrNo(bool? defaultAnswer = null)
{
while (true)
{
var input = Console.ReadLine();
if (input.IsYes())
return true;
if (input.IsNo())
return false;
if (defaultAnswer != null)
return defaultAnswer.Value;
Console.WriteLine("Please answer by yes or no");
}
}

public static string GetNewSeedPass()
{
string? pin;
Console.WriteLine("========================================================================");
Console.WriteLine("Please enter the cipher seed passphrase to secure your seed on disk ");
Console.WriteLine("It is recommended to be longer than 10 characters to be cryptographically secure");
Console.WriteLine("Please do not forget this cipher seed passphrase. You will need it when restarting" +
"the server");
Console.WriteLine("========================================================================");
while (true)
{
Console.WriteLine("Please enter your cipher seed passphrase: ");
var pin1 = Console.ReadLine();
if (string.IsNullOrEmpty(pin1?.Trim()))
{
Console.WriteLine($"Are you sure you want to use empty pin code? [y/N]");
var isYes = CliUtils.AskUserYesOrNo(false);
if (isYes)
return "";
else
continue;
}
Console.WriteLine("Please enter again:");
var pin2 = Console.ReadLine();
if (pin1 == pin2)
{
pin = pin1;
break;
}
else
{
Console.WriteLine("cipher seed passphrase mismatch! try again");
}
}
return pin;
}

public static string GetMnemonic()
{
}

public static string GetSeedPass(byte[] encipheredCipherSeed)
{
if (encipheredCipherSeed.Length != 33)
throw new ConfigException($"{nameof(encipheredCipherSeed)} must be length 33! It was {encipheredCipherSeed.Length}");
string? seedPass;
bool isValid;
while (true)
{
Console.WriteLine("Please enter your cipher seed passphrase: ");
var pin1 = Console.ReadLine();
Console.WriteLine("Please enter again:");
var pin2 = Console.ReadLine();
if (pin1 == pin2)
{
seedPass = pin1;
break;
}
Console.WriteLine("cipher seed passphrase mismatch! try again");
}
return seedPass;
}
}
}
26 changes: 26 additions & 0 deletions src/NRustLightning.Infrastructure/Utils/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;

namespace NRustLightning.Infrastructure.Utils
{
public static class Extensions
{
public static bool IsYes(this string userInput) => userInput switch
{
"yes" => true,
"Yes" => true,
"y" => true,
"Y" => true,
_ => false
};

public static bool IsNo(this string userInput) => userInput switch
{
"no" => true,
"No" => true,
"n" => true,
"N" => true,
_ => false
};

}
}
2 changes: 2 additions & 0 deletions src/NRustLightning.Infrastructure/Utils/Utils.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using NRustLightning.Infrastructure.Models.Response;
Expand All @@ -18,5 +19,6 @@ public static T Fail<T>(string msg) where T : class
{
throw Fail(msg);
}

}
}
12 changes: 5 additions & 7 deletions src/NRustLightning.Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using DotNetLightning.Chain;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
Expand All @@ -17,11 +15,12 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

using DotNetLightning.Crypto;
using NBitcoin;
using NRustLightning.Infrastructure.Configuration;
using NRustLightning.Infrastructure.Configuration.SubConfiguration;
using NRustLightning.Infrastructure.Repository;
using NRustLightning.Interfaces;
using NRustLightning.Infrastructure.Utils;
using NRustLightning.Server.Configuration;
using NRustLightning.Server.P2P;
using IKeysRepository = NRustLightning.Infrastructure.Interfaces.IKeysRepository;
Expand Down Expand Up @@ -50,10 +49,10 @@ public static async Task Main(string[] args)
else
{
var maybeEncryptedSeed = await conf.Value.TryGetEncryptedSeed();
var pin = CliUtils.GetNewSeedPass();
if (maybeEncryptedSeed != null)
{
var isValidPin = false;
var pin = conf.Value.Pin;
var maybeErrMsg = repo.InitializeFromEncryptedSeed(maybeEncryptedSeed, pin);
if (maybeErrMsg is null)
{
Expand Down Expand Up @@ -82,8 +81,7 @@ public static async Task Main(string[] args)
else
{
logger.LogWarning($"seed not found in {conf.Value.SeedFilePath}! generating new seed...");
var pin = conf.Value.GetNewPin();
var seed = RandomUtils.GetUInt256().ToString();
var seed = CipherSeed.Create();
repo.InitializeFromSeed(seed);
await repo.EncryptSeedAndSaveToFile(seed, pin);
}
Expand Down
2 changes: 1 addition & 1 deletion src/NRustLightning/Interfaces/IBroadcaster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal struct BroadcasterDelegatesHolder : IDisposable
private readonly IBroadcaster _broadcaster;
private readonly Network _n;
private readonly BroadcastTransaction _broadcastTransaction;
public BroadcasterDelegatesHolder(IBroadcaster broadcaster, NBitcoin.Network n)
public BroadcasterDelegatesHolder(IBroadcaster broadcaster, Network n)
{
_broadcaster = broadcaster ?? throw new ArgumentNullException(nameof(broadcaster));
_n = n ?? throw new ArgumentNullException(nameof(n));
Expand Down