From 581677691de8ccba0b57143811ff6ecc54f2ab57 Mon Sep 17 00:00:00 2001 From: adi2011 Date: Mon, 31 Jul 2023 09:03:33 +0930 Subject: [PATCH] lightningd/common: Added --recover flag to populate HSM_secret with appropriate secret through a valid codex32 secret. --- lightningd/Makefile | 1 + lightningd/options.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/lightningd/Makefile b/lightningd/Makefile index b867e56ce..8815c0e10 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -84,6 +84,7 @@ LIGHTNINGD_COMMON_OBJS := \ common/bolt11_json.o \ common/bolt12.o \ common/bolt12_merkle.o \ + common/codex32.o \ common/channel_config.o \ common/channel_id.o \ common/channel_type.o \ diff --git a/lightningd/options.c b/lightningd/options.c index 004ec5411..db647b131 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -4,11 +4,15 @@ #include #include #include +#include #include #include +#include #include +#include #include #include +#include #include #include #include @@ -20,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1253,6 +1258,74 @@ static char *opt_set_announce_dns(const char *optarg, struct lightningd *ld) return opt_set_bool_arg(optarg, &ld->announce_dns); } +static char *opt_set_codex32(const char *arg, struct lightningd *ld) +{ + const uint8_t *payload; + char *err; + struct codex32 *parts = codex32_decode(tmpctx, arg, &err); + + if (!parts) { + return err; + } + + if (parts->type != CODEX32_ENCODING_SECRET) { + return tal_fmt(tmpctx, "Not a valid codex32 secret!"); + } + + payload = codex32_decode_payload(tmpctx, parts); + if (tal_bytelen(payload) != 32) { + return tal_fmt(tmpctx, "Expected 32 Byte secret: %s", + tal_hexstr(tmpctx, + payload, + tal_bytelen(payload))); + } + + /* Checks if hsm_secret exists */ + int fd = open("hsm_secret", O_CREAT|O_EXCL|O_WRONLY, 0400); + if (fd < 0) { + /* Don't do anything if the file already exists. */ + if (errno == EEXIST) + return tal_fmt(tmpctx, "hsm_secret already exists!"); + + return tal_fmt(tmpctx, "Creating hsm_secret: %s", + strerror(errno)); + } + + if (!write_all(fd, payload, tal_count(payload))) { + unlink_noerr("hsm_secret"); + return tal_fmt(tmpctx, "Writing HSM: %s", + strerror(errno)); + } + + /*~ fsync (mostly!) ensures that the file has reached the disk. */ + if (fsync(fd) != 0) { + unlink_noerr("hsm_secret"); + return tal_fmt(tmpctx, "fsync: %s", strerror(errno)); + } + /*~ This should never fail if fsync succeeded. But paranoia good, and + * bugs exist. */ + if (close(fd) != 0) { + unlink_noerr("hsm_secret"); + return tal_fmt(tmpctx, "closing: %s", strerror(errno)); + } + + /*~ We actually need to sync the *directory itself* to make sure the + * file exists! You're only allowed to open directories read-only in + * modern Unix though. */ + fd = open(".", O_RDONLY); + if (fd < 0) { + unlink_noerr("hsm_secret"); + return tal_fmt(tmpctx, "opening: %s", strerror(errno)); + } + if (fsync(fd) != 0) { + unlink_noerr("hsm_secret"); + return tal_fmt(tmpctx, "fsyncdir: %s", strerror(errno)); + } + close(fd); + + return NULL; +} + static void register_opts(struct lightningd *ld) { /* This happens before plugins started */ @@ -1300,6 +1373,11 @@ static void register_opts(struct lightningd *ld) &ld->wallet_dsn, "Location of the wallet database."); + opt_register_early_arg("--recover", opt_set_codex32, NULL, + ld, + "Populate hsm_secret with the given codex32 secret" + " and starts the node in `offline` mode."); + /* This affects our features, so set early. */ opt_register_early_noarg("--large-channels|--wumbo", opt_set_wumbo, ld, @@ -1964,6 +2042,7 @@ bool is_known_opt_cb_arg(char *(*cb_arg)(const char *, void *)) || cb_arg == (void *)opt_set_db_upgrade || cb_arg == (void *)arg_log_to_file || cb_arg == (void *)opt_add_accept_htlc_tlv + || cb_arg == (void *)opt_set_codex32 #if DEVELOPER || cb_arg == (void *)opt_subd_dev_disconnect || cb_arg == (void *)opt_force_featureset