We would like to allow users to restore their databases from an IPNS pointer based on IPFS key names that they maintain. However, due to there being only two endpoints for IPNS name/resolve
and name/publish,
it doesnt appear that one can derive the IPNS name from a key without re-pointing the IPNS name. Is it possible?
I have found that the keys all exist in the keystore
fodler inside of IPFS_HOME
, but I'm not sure about the format of these files. The comments here suggest that they are in protobuf format, but I'm not sure how to extract the data meaningfully from there.
For example, using --decode-raw
gives me this:
root@ip-172-31-11-196:~# protoc --decode_raw $IPFS_HOME/keystore/keypairfile
1: 0
2: "0\202\004\243\002\001\000\002\202\001\001\000\333\246v\\+s\350\321`8Y\224Y\353I\267h\254\257\334\356Q\276W\017ZA\357\327\331\t\304?\327Y\312tP\201\377\235^\014\376\245Q1*[n\004Lh\377\256F\350\235yr\231\233\353\237D~\321\254j\252\273I[\245rv\3046\3441WO\257\252+\273|\216\207\204z<~2K\265\362\224\016\246\334+\373JE\326\371\n\032,n\025\266\335\374\244\202\242\364>\033\275\345l\327\350\353\\\206~*h\237\223\321\337\037P\212\227\204\014W;\205\314pE\256\207\200\t\3275\256\234\'K\177E\253\355c\225\340\251\370\222\371\247\366\353\0140}\312J\254\267+\007\323\366\357\350\244>[\203\031Z\217\311\'\324_o\017\307\262\034\234F4\267\014\343\221NM\221\214\230\034D*-Pa\315%\2513\016H\311\375\004\345\243Q2\277\007\330\217\363\306\272{\357\237\252\204\332\301q\276\000\362\032\212\212\202I\031\002\003\001\000\001\002\202\001\000\002\003\247\3106\231\314\203\307\007\035C0\003\351\\&8\2270F{7l\242\366g\356d#Xd\225UK<\201\016\217\362\241%\320\246\261+jq\001\377\243Ht\032\014&\030R\001`\034\252\202a\246\206\'4\026\222T?Z\370\314p\354a\270{\377Y\372\271k\307?`+;\372\306\375=F\326wP\006F_t\203\314m\221\210\035 \232Q\264\037F/\337\356V\3028\243\226}9\037M\302\202\305Z%\355\007\010\337\316L\276\203%\233\031\216\010P\235\t\307\372\203\362\206\265\327\022W\032\327e\213k?\001\314\324k\022\303\306W\25798\350\240\357\334\311Ft\275\204\342\207^\326k-)]eD\341\007\372\377-J\261\\cJh\246\212\010\025\t\252Q\\\340\221\330\277q\t6\210${\222\225y\260\266\r\204\014P\257\262DR\307\001\216\250$\212\220\362xp\311\022\321\357*\2309\t\232\342\260\001\002\201\201\000\371p|\305\276\276*\253%\244\276\360i\203Y\002\2217$\372g\017WT!C\225\362n\377`\r\t\203(q\353\323K\202\356X\273B\341\037p\t\017\354|+_\317\313k\210\335\000Fr3pqW\001>G\243\231y\373p7\335\201K\362>\333]Od\365\255\360\373\214\245\237\267R\354GA\366\016W\371@*s05`>}\217\361\363PU2]\225\226]=\356n\005\236P\307w\353\342\001\002\201\201\000\341mfm9y\266\343\251>\314\007C\310\324\210\302\230\210\237\353\021|W\330\035w\223~\'SD9r\272\377;)\250\336)[X<XH\021a\024\3108o\261\214\007\240\301\326\222,\260e\001m\370\320\032\354\246u\231\177\337\227\371\214]\242~{o\020h@\220(-\337FF\340\221X\340\001*\t\376\350\343\345\345\224\336\261g>\276\215\252\335H\233\227\210\256\315\302\372(\376\221\265c\260\3537\031\002\201\200O9A\367\320h7\307\031\362\244NYD\305m\202O\300g\343y\304\343\314\230\331\264!:\354\367\327\020\2304\356\220\262\210\010I\230XZ\206\020\240`5]\016\255\244\242\330)\244\377\244`;$8kH\322\316\020\020\373\34475\027\036,\317\350\324\345c\005\016\336\313\016*\022\244\222\246<\2639(\374OF\263\361\207\232E)\247O[\373\235\252\343\024W\022\336\252\010\264\204\2576$3\346K\276\001\002\201\200\023\347\320\"\226\357\253y\240\351=\244\352\224bH\r>\340\331\226->\030\227\251\312tH\260zF\314\367\327\221P\r\026\257?a\244\201\367\235\255\2030\r\232\006*\334]\224\021i\274\020\234&\337 q\327\026y\215\035WG\226[\332\032M\356ZR\325\364\321\357\331\212\342\272\023\177\220\266\344\355*\315&\202\316\327\310\346#\346\".&\2716\323>\244\371\260@\316\206\266\317\326,\334z\362\351\235k\211\002\201\201\000\311\231\273\205\340\260\0360\252\236G\221\305\201!\305\013\013\\\217N\332\004\364>\314\nP\016\375-\240b\\\246=\264C\t\357\362\303xC\327P\353\034\224\023Xn\204\360\300A3\001N\262\3233r\004\346v\300v\"g\315\034\275\001L;4,\224\302\376\372\324\037Z\232\245)2\364\034\177\307\341\0045(\326\360\3311\265\002\231\265Y\014Cb%\202uB\033\313\177-kr\345\026\247\357\237\247+\310\272"
Which appears to be two binary items, but still nothing I can quite extract the IPNS name from... or is it?
Here's a working example in Go of how to read the RSA key pair and base58 encode the public key to get the IPNS peer ID:
package main
import (
"bufio"
"bytes"
"encoding/pem"
"fmt"
"log"
"github.com/ipfs/go-ipfs/keystore"
b58 "github.com/mr-tron/base58/base58"
mh "github.com/multiformats/go-multihash"
)
func main() {
ks, err := keystore.NewFSKeystore("/Users/username/.ipfs/keystore/")
if err != nil {
log.Fatal(err)
}
priv, err := ks.Get("mykey")
if err != nil {
log.Fatal(err)
}
privBytes, err := priv.Bytes()
if err != nil {
log.Fatal(err)
}
var privPEM bytes.Buffer
privWriter := bufio.NewWriter(&privPEM)
pem.Encode(privWriter, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privBytes,
})
privWriter.Flush()
pub := priv.GetPublic()
var pubPEM bytes.Buffer
pubBytes, err := pub.Bytes()
pubWriter := bufio.NewWriter(&pubPEM)
pem.Encode(pubWriter, &pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubBytes,
})
pubWriter.Flush()
privPEMString := string(privPEM.Bytes())
pubPEMString := string(pubPEM.Bytes())
var alg uint64 = mh.SHA2_256
maxInlineKeyLength := 42
if len(pubBytes) <= maxInlineKeyLength {
alg = mh.ID
}
hash, _ := mh.Sum(pubBytes, alg, -1)
peerID := b58.Encode(hash)
fmt.Println(privPEMString)
fmt.Println(pubPEMString)
fmt.Println("IPNS:", peerID)
}
Output:
-----BEGIN RSA PRIVATE KEY-----
CAASpwkwggSjAgEAAoIBAQDjwkdyAvwfL6zIr2O6MF2ipNd/pkkV+5+9wOyvAL9I
HY4WRMmmLBGiBTj1Kln79ttChegxy/XME7ipzt2KXq7qaMT7ZiscB0pPpLCpViue
GxY90VbYmTeUrtvFJ+fJ5k4InuYtxJpwIpK0zkTZEQbq7mjOOl0VaIzH4iBjKKDq
uYXxX5JSz5/9I2a4d5YvOoci703krFEAGw4FsnUR+NU0wKE2A66+t+xml3E6D/Oo
OowSzLk2o0vZOFqNG4/tas9HGKYO8ofmFYMhbw5j/p3lZCHhPdklZZ4nlrEZIxPT
lwdeY3qBG+7WyzctLbJLerg8cvwOJ5m46uQ4f0j4mYf9AgMBAAECggEAQPhftxdA
4oiQCmN12FwJqebKDoDZ4mp4BAIvwjA9YI4FxTZ0K3Hwyb4hpFYjeyvNGinmtaXQ
BRovGEmJivo9fWLLpkdbztAJk7SQLI4HPT/O1W2ND5aNc116FcCvbznCUtU5Jh8q
SwihvvAEVcN0rLm7rfCaMwwy9KX9xSuG0830suMmVJ31W0evzRYHtnsvmDC9rdrA
TOy2HZdbL5Bty+nSwOlD608hCPWG6jCH5/BpEA3nCGX6KGH4yqFjaWGRA54cGGsh
bcKP1Hsdk0zle+Epl04yR1h2XCuwfmM3yegZuKjG5dfF51kV0yq2kND4F47D5azp
QJEhYHHOi6dvhQKBgQDwhZVl0W1rZjUvzkf/mZ2uC7aL64Rg1DFWNpSc05NK4IBS
eAf17HCCxLHCZnR0r8+CC0bOR+0xFT24RKcDyiPzpUo90LKHV3CXZEeFEWwfCg6N
RUfKMVLu9Vf5z7U4V2lOkojE7pWLt/ZMEAxXByQPlNyARfiRI8HPsPgrTlJvKwKB
gQDyam+oJbAfLvEFQ+h0B1ov3/3BEzV3GRkRz/IHTzQvHKyrN8zn/NZzQfrv3GR8
5W9BumpdfPkV5kCJb00fjS7AgLGWGHBsqzyDdliZdiQ5h5b15SflDrzfCF6c23lp
iizEtoNWTFYpgp3MuXYtfvr+6p6VdwZkZ5xTUebK4bIRdwKBgErJnqysNBPDEiKt
R6HoiCkIJ1jWgLEDCdw+2HLzLseHix8Zh5AmVs2yj3tdFDT8Pc+35epaXxx1+F0F
q9D317n42V7jN7/xpmbMnZh41F/KZr/ynOH3+EupKhPZTAYa1/nAgpqJfSKWrxTz
oIKnC8V0iiOwnhuzPJ5x7pi4n9VFAoGBAMV7OdzkXvb4WbatXJfxSWJI+kKosFyG
oKqnGYck2eErXerZuV6f1d/tN0zh4SbyDdGg2HeykIRrn9WWS2DRte1yqbkZzbRp
RxHdfk3+NYJ8V9mXxglPGUQkYFcuYFk/DDtwZ8wMwgBs/LpDt+dWU4kJfwlJ/nYb
BfnGddp/RH3/AoGAYxXvoxuhGzMXvDLNJ0SNuqNUfZ/F/ltMAcPmhtJkTo+RpZlm
eBvXrduLemNPYcNxTNmuRMgA4kVHOlu+/s7VQ4sRcNp7Fgau3+aqkE/9pkV3wJnf
xTlPlC4y+VeMKqBczpIXBD42mQMSwe9x/chOVQ+oebqB6Nvyk8RbcI9fJEs=
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PUBLIC KEY-----
CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjwkdyAvwfL6zI
r2O6MF2ipNd/pkkV+5+9wOyvAL9IHY4WRMmmLBGiBTj1Kln79ttChegxy/XME7ip
zt2KXq7qaMT7ZiscB0pPpLCpViueGxY90VbYmTeUrtvFJ+fJ5k4InuYtxJpwIpK0
zkTZEQbq7mjOOl0VaIzH4iBjKKDquYXxX5JSz5/9I2a4d5YvOoci703krFEAGw4F
snUR+NU0wKE2A66+t+xml3E6D/OoOowSzLk2o0vZOFqNG4/tas9HGKYO8ofmFYMh
bw5j/p3lZCHhPdklZZ4nlrEZIxPTlwdeY3qBG+7WyzctLbJLerg8cvwOJ5m46uQ4
f0j4mYf9AgMBAAE=
-----END RSA PUBLIC KEY-----
IPNS: QmTU9rhcwQM6refNwa64oqibG6C2mmFLhhxDBUjWDBtRa6
The key was generated by doing:
ipfs key gen mykey --type=rsa --size=2048
It'll be a very similar process for other languages such as Node.js