22 changed files with 425 additions and 63 deletions
@ -0,0 +1,180 @@
@@ -0,0 +1,180 @@
|
||||
package app |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
database "database.orly" |
||||
"database.orly/indexes/types" |
||||
"encoders.orly/envelopes/eventenvelope" |
||||
"encoders.orly/event" |
||||
"encoders.orly/filter" |
||||
"encoders.orly/hex" |
||||
"encoders.orly/ints" |
||||
"encoders.orly/kind" |
||||
"encoders.orly/tag" |
||||
"encoders.orly/tag/atag" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
utils "utils.orly" |
||||
) |
||||
|
||||
func (l *Listener) GetSerialsFromFilter(f *filter.F) ( |
||||
sers types.Uint40s, err error, |
||||
) { |
||||
var idxs []database.Range |
||||
if idxs, err = database.GetIndexesFromFilter(f); chk.E(err) { |
||||
return |
||||
} |
||||
for _, idx := range idxs { |
||||
var s types.Uint40s |
||||
if s, err = l.GetSerialsByRange(idx); chk.E(err) { |
||||
continue |
||||
} |
||||
sers = append(sers, s...) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func (l *Listener) HandleDelete(env *eventenvelope.Submission) { |
||||
log.T.C( |
||||
func() string { |
||||
return fmt.Sprintf( |
||||
"delete event\n%s", env.E.Serialize(), |
||||
) |
||||
}, |
||||
) |
||||
var ownerDelete bool |
||||
for _, pk := range l.Admins { |
||||
if utils.FastEqual(pk, env.E.Pubkey) { |
||||
ownerDelete = true |
||||
break |
||||
} |
||||
} |
||||
// process the tags in the delete event
|
||||
var err error |
||||
for _, t := range *env.E.Tags { |
||||
// first search for a tags, as these are the simplest to process
|
||||
if utils.FastEqual(t.Key(), []byte("a")) { |
||||
at := new(atag.T) |
||||
if _, err = at.Unmarshal(t.Value()); chk.E(err) { |
||||
continue |
||||
} |
||||
if ownerDelete || utils.FastEqual(env.E.Pubkey, at.Pubkey) { |
||||
// find the event and delete it
|
||||
f := &filter.F{ |
||||
Authors: tag.NewFromBytesSlice(at.Pubkey), |
||||
Kinds: kind.NewS(at.Kind), |
||||
} |
||||
if len(at.DTag) > 0 { |
||||
f.Tags = tag.NewS( |
||||
tag.NewFromAny("d", at.DTag), |
||||
) |
||||
} |
||||
var sers types.Uint40s |
||||
if sers, err = l.GetSerialsFromFilter(f); chk.E(err) { |
||||
continue |
||||
} |
||||
// if found, delete them
|
||||
if len(sers) > 0 { |
||||
for _, s := range sers { |
||||
var ev *event.E |
||||
if ev, err = l.FetchEventBySerial(s); chk.E(err) { |
||||
continue |
||||
} |
||||
if !(kind.IsReplaceable(ev.Kind) && len(at.DTag) == 0) { |
||||
// skip a tags with no dtag if the kind is not
|
||||
// replaceable.
|
||||
continue |
||||
} |
||||
if err = l.DeleteEventBySerial( |
||||
l.Ctx, s, ev, |
||||
); chk.E(err) { |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
} |
||||
continue |
||||
} |
||||
// if e tags are found, delete them if the author is signer, or one of
|
||||
// the owners is signer
|
||||
if utils.FastEqual(t.Key(), []byte("e")) { |
||||
var dst []byte |
||||
if _, err = hex.DecBytes(dst, t.Value()); chk.E(err) { |
||||
continue |
||||
} |
||||
f := &filter.F{ |
||||
Ids: tag.NewFromBytesSlice(dst), |
||||
} |
||||
var sers types.Uint40s |
||||
if sers, err = l.GetSerialsFromFilter(f); chk.E(err) { |
||||
continue |
||||
} |
||||
// if found, delete them
|
||||
if len(sers) > 0 { |
||||
// there should be only one event per serial, so we can just
|
||||
// delete them all
|
||||
for _, s := range sers { |
||||
var ev *event.E |
||||
if ev, err = l.FetchEventBySerial(s); chk.E(err) { |
||||
continue |
||||
} |
||||
// check that the author is the same as the signer of the
|
||||
// delete, for the k tag case the author is the signer of
|
||||
// the event.
|
||||
if !utils.FastEqual(env.E.Pubkey, ev.Pubkey) { |
||||
continue |
||||
} |
||||
// exclude delete events
|
||||
if ev.Kind == kind.EventDeletion.K { |
||||
continue |
||||
} |
||||
if err = l.DeleteEventBySerial(l.Ctx, s, ev); chk.E(err) { |
||||
continue |
||||
} |
||||
} |
||||
continue |
||||
} |
||||
} |
||||
// if k tags are found, check they are replaceable
|
||||
if utils.FastEqual(t.Key(), []byte("k")) { |
||||
ki := ints.New(0) |
||||
if _, err = ki.Unmarshal(t.Value()); chk.E(err) { |
||||
continue |
||||
} |
||||
kn := ki.Uint16() |
||||
// skip events that are delete events or that are not replaceable
|
||||
if !kind.IsReplaceable(kn) || kn != kind.EventDeletion.K { |
||||
continue |
||||
} |
||||
f := &filter.F{ |
||||
Authors: tag.NewFromBytesSlice(env.E.Pubkey), |
||||
Kinds: kind.NewS(kind.New(kn)), |
||||
} |
||||
var sers types.Uint40s |
||||
if sers, err = l.GetSerialsFromFilter(f); chk.E(err) { |
||||
continue |
||||
} |
||||
// if found, delete them
|
||||
if len(sers) > 0 { |
||||
// there should be only one event per serial because replaces
|
||||
// delete old ones, so we can just delete them all
|
||||
for _, s := range sers { |
||||
var ev *event.E |
||||
if ev, err = l.FetchEventBySerial(s); chk.E(err) { |
||||
continue |
||||
} |
||||
// check that the author is the same as the signer of the
|
||||
// delete, for the k tag case the author is the signer of
|
||||
// the event.
|
||||
if !utils.FastEqual(env.E.Pubkey, ev.Pubkey) { |
||||
continue |
||||
} |
||||
} |
||||
continue |
||||
} |
||||
} |
||||
continue |
||||
} |
||||
return |
||||
} |
||||
@ -0,0 +1,143 @@
@@ -0,0 +1,143 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"flag" |
||||
"fmt" |
||||
"os" |
||||
"strings" |
||||
|
||||
"crypto.orly/ec/schnorr" |
||||
"crypto.orly/ec/secp256k1" |
||||
b32 "encoders.orly/bech32encoding" |
||||
"encoders.orly/hex" |
||||
) |
||||
|
||||
func usage() { |
||||
fmt.Fprintf(os.Stderr, "Usage: convert [--secret] <key>\n") |
||||
fmt.Fprintf( |
||||
os.Stderr, " <key> can be hex (64 chars) or bech32 (npub/nsec).\n", |
||||
) |
||||
fmt.Fprintf( |
||||
os.Stderr, |
||||
" --secret: interpret input key as a secret key; print both nsec and npub in hex and bech32.\n"+ |
||||
" --secret is implied if <key> starts with nsec.\n", |
||||
) |
||||
} |
||||
|
||||
func main() { |
||||
var isSecret bool |
||||
flag.BoolVar( |
||||
&isSecret, "secret", false, "interpret the input as a secret key", |
||||
) |
||||
flag.Parse() |
||||
|
||||
if flag.NArg() < 1 { |
||||
usage() |
||||
os.Exit(2) |
||||
} |
||||
|
||||
input := strings.TrimSpace(flag.Arg(0)) |
||||
|
||||
// Auto-detect secret if input starts with nsec
|
||||
if strings.HasPrefix(input, string(b32.SecHRP)) { |
||||
isSecret = true |
||||
} |
||||
|
||||
if isSecret { |
||||
if err := handleSecret(input); err != nil { |
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err) |
||||
os.Exit(1) |
||||
} |
||||
return |
||||
} |
||||
|
||||
if err := handlePublic(input); err != nil { |
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err) |
||||
os.Exit(1) |
||||
} |
||||
} |
||||
|
||||
func handleSecret(input string) error { |
||||
// Accept nsec bech32 or 64-char hex as secret key
|
||||
var sk *secp256k1.SecretKey |
||||
var err error |
||||
|
||||
if strings.HasPrefix(input, string(b32.SecHRP)) { // nsec...
|
||||
if sk, err = b32.NsecToSecretKey([]byte(input)); err != nil { |
||||
return fmt.Errorf("failed to decode nsec: %w", err) |
||||
} |
||||
} else { |
||||
// Expect hex
|
||||
if len(input) != b32.HexKeyLen { |
||||
return fmt.Errorf("secret key hex must be %d chars", b32.HexKeyLen) |
||||
} |
||||
var b []byte |
||||
if b, err = hex.Dec(input); err != nil { |
||||
return fmt.Errorf("invalid secret hex: %w", err) |
||||
} |
||||
sk = secp256k1.SecKeyFromBytes(b) |
||||
} |
||||
|
||||
// Prepare outputs for secret
|
||||
nsec, err := b32.SecretKeyToNsec(sk) |
||||
if err != nil { |
||||
return fmt.Errorf("encode nsec: %w", err) |
||||
} |
||||
secHex := hex.EncAppend(nil, sk.Serialize()) |
||||
|
||||
// Derive public key
|
||||
pk := sk.PubKey() |
||||
npub, err := b32.PublicKeyToNpub(pk) |
||||
if err != nil { |
||||
return fmt.Errorf("encode npub: %w", err) |
||||
} |
||||
pkBytes := schnorr.SerializePubKey(pk) |
||||
pkHex := hex.EncAppend(nil, pkBytes) |
||||
|
||||
// Print results
|
||||
fmt.Printf("nsec (hex): %s\n", string(secHex)) |
||||
fmt.Printf("nsec (bech32): %s\n", string(nsec)) |
||||
fmt.Printf("npub (hex): %s\n", string(pkHex)) |
||||
fmt.Printf("npub (bech32): %s\n", string(npub)) |
||||
return nil |
||||
} |
||||
|
||||
func handlePublic(input string) error { |
||||
// Accept npub bech32, nsec bech32 (derive pub), or 64-char hex pubkey
|
||||
var pubBytes []byte |
||||
var err error |
||||
|
||||
if strings.HasPrefix(input, string(b32.PubHRP)) { // npub...
|
||||
if pubBytes, err = b32.NpubToBytes([]byte(input)); err != nil { |
||||
return fmt.Errorf("failed to decode npub: %w", err) |
||||
} |
||||
} else if strings.HasPrefix( |
||||
input, string(b32.SecHRP), |
||||
) { // nsec without --secret: show pub only
|
||||
var sk *secp256k1.SecretKey |
||||
if sk, err = b32.NsecToSecretKey([]byte(input)); err != nil { |
||||
return fmt.Errorf("failed to decode nsec: %w", err) |
||||
} |
||||
pubBytes = schnorr.SerializePubKey(sk.PubKey()) |
||||
} else { |
||||
// Expect hex pubkey
|
||||
if len(input) != b32.HexKeyLen { |
||||
return fmt.Errorf("public key hex must be %d chars", b32.HexKeyLen) |
||||
} |
||||
if pubBytes, err = hex.Dec(input); err != nil { |
||||
return fmt.Errorf("invalid public hex: %w", err) |
||||
} |
||||
} |
||||
|
||||
// Compute encodings
|
||||
npub, err := b32.BinToNpub(pubBytes) |
||||
if err != nil { |
||||
return fmt.Errorf("encode npub: %w", err) |
||||
} |
||||
pubHex := hex.EncAppend(nil, pubBytes) |
||||
|
||||
// Print only pubkey representations
|
||||
fmt.Printf("npub (hex): %s\n", string(pubHex)) |
||||
fmt.Printf("npub (bech32): %s\n", string(npub)) |
||||
return nil |
||||
} |
||||
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
package constraints |
||||
|
||||
type Bytes interface { |
||||
~string | ~[]byte |
||||
} |
||||
Loading…
Reference in new issue