From 7ef36f569b626c20a07c5e288695da14699adc11 Mon Sep 17 00:00:00 2001 From: Marco Peereboom Date: Wed, 8 Jan 2025 11:23:28 +0000 Subject: [PATCH 1/2] Remove pubkey access --- api/bfgapi/bfgapi.go | 26 +- cmd/bfgd/bfgd.go | 8 +- database/bfgd/database.go | 6 +- database/bfgd/postgres/postgres.go | 69 +--- e2e/e2e_ext_test.go | 589 +---------------------------- service/bfg/bfg.go | 106 +----- 6 files changed, 11 insertions(+), 793 deletions(-) diff --git a/api/bfgapi/bfgapi.go b/api/bfgapi/bfgapi.go index f12ccb0b..bd986e50 100644 --- a/api/bfgapi/bfgapi.go +++ b/api/bfgapi/bfgapi.go @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Hemi Labs, Inc. +// Copyright (c) 2024-2025 Hemi Labs, Inc. // Use of this source code is governed by the MIT License, // which can be found in the LICENSE file. @@ -40,10 +40,6 @@ const ( CmdBitcoinInfoResponse = "bfgapi-bitcoin-info-response" CmdBitcoinUTXOsRequest = "bfgapi-bitcoin-utxos-request" CmdBitcoinUTXOsResponse = "bfgapi-bitcoin-utxos-response" - CmdAccessPublicKeyCreateRequest = "bfgapi-access-public-key-create-request" - CmdAccessPublicKeyCreateResponse = "bfgapi-access-public-key-create-response" - CmdAccessPublicKeyDeleteRequest = "bfgapi-access-public-key-delete-request" - CmdAccessPublicKeyDeleteResponse = "bfgapi-access-public-key-delete-response" ) var ( @@ -164,22 +160,6 @@ type BTCNewBlockNotification struct{} type L2KeystonesNotification struct{} -type AccessPublicKeyCreateRequest struct { - PublicKey string `json:"public_key"` // encoded compressed public key -} - -type AccessPublicKeyCreateResponse struct { - Error *protocol.Error `json:"error,omitempty"` -} - -type AccessPublicKeyDeleteRequest struct { - PublicKey string `json:"public_key"` -} - -type AccessPublicKeyDeleteResponse struct { - Error *protocol.Error `json:"error,omitempty"` -} - type PopTx struct { BtcTxId api.ByteSlice `json:"btc_tx_id"` BtcRawTx api.ByteSlice `json:"btc_raw_tx"` @@ -215,10 +195,6 @@ var commands = map[protocol.Command]reflect.Type{ CmdBitcoinInfoResponse: reflect.TypeOf(BitcoinInfoResponse{}), CmdBitcoinUTXOsRequest: reflect.TypeOf(BitcoinUTXOsRequest{}), CmdBitcoinUTXOsResponse: reflect.TypeOf(BitcoinUTXOsResponse{}), - CmdAccessPublicKeyCreateRequest: reflect.TypeOf(AccessPublicKeyCreateRequest{}), - CmdAccessPublicKeyCreateResponse: reflect.TypeOf(AccessPublicKeyCreateResponse{}), - CmdAccessPublicKeyDeleteRequest: reflect.TypeOf(AccessPublicKeyDeleteRequest{}), - CmdAccessPublicKeyDeleteResponse: reflect.TypeOf(AccessPublicKeyDeleteResponse{}), } type bfgAPI struct{} diff --git a/cmd/bfgd/bfgd.go b/cmd/bfgd/bfgd.go index d0278e25..06b4fc36 100644 --- a/cmd/bfgd/bfgd.go +++ b/cmd/bfgd/bfgd.go @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Hemi Labs, Inc. +// Copyright (c) 2024-2025 Hemi Labs, Inc. // Use of this source code is governed by the MIT License, // which can be found in the LICENSE file. @@ -49,12 +49,6 @@ var ( Help: "electrs max connections", Print: config.PrintAll, }, - "BFG_PUBLIC_KEY_AUTH": config.Config{ - Value: &cfg.PublicKeyAuth, - DefaultValue: false, - Help: "enable enforcing of public key auth handshake", - Print: config.PrintAll, - }, "BFG_BTC_START_HEIGHT": config.Config{ Value: &cfg.BTCStartHeight, DefaultValue: uint64(0), diff --git a/database/bfgd/database.go b/database/bfgd/database.go index 6d5b4681..bf99e6e4 100644 --- a/database/bfgd/database.go +++ b/database/bfgd/database.go @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Hemi Labs, Inc. +// Copyright (c) 2024-2025 Hemi Labs, Inc. // Use of this source code is governed by the MIT License, // which can be found in the LICENSE file. @@ -38,10 +38,6 @@ type Database interface { BtcBlockCanonicalHeight(ctx context.Context) (uint64, error) - AccessPublicKeyInsert(ctx context.Context, publicKey *AccessPublicKey) error - AccessPublicKeyExists(ctx context.Context, publicKey *AccessPublicKey) (bool, error) - AccessPublicKeyDelete(ctx context.Context, publicKey *AccessPublicKey) error - BtcTransactionBroadcastRequestInsert(ctx context.Context, serializedTx []byte, txId string) error BtcTransactionBroadcastRequestGetNext(ctx context.Context, onlyNew bool) ([]byte, error) BtcTransactionBroadcastRequestConfirmBroadcast(ctx context.Context, txId string) error diff --git a/database/bfgd/postgres/postgres.go b/database/bfgd/postgres/postgres.go index 4db58aae..2347c254 100644 --- a/database/bfgd/postgres/postgres.go +++ b/database/bfgd/postgres/postgres.go @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Hemi Labs, Inc. +// Copyright (c) 2024-2025 Hemi Labs, Inc. // Use of this source code is governed by the MIT License, // which can be found in the LICENSE file. @@ -20,7 +20,7 @@ import ( ) const ( - bfgdVersion = 11 + bfgdVersion = 12 logLevel = "INFO" verbose = false @@ -908,71 +908,6 @@ func (p *pgdb) BtcBlockCanonicalHeight(ctx context.Context) (uint64, error) { return result, nil } -func (p *pgdb) AccessPublicKeyInsert(ctx context.Context, publicKey *bfgd.AccessPublicKey) error { - log.Tracef("AccessPublicKeyInsert") - defer log.Tracef("AccessPublicKeyInsert exit") - - const sql = ` - INSERT INTO access_public_keys ( - public_key - ) VALUES ($1) - ` - - _, err := p.db.ExecContext(ctx, sql, publicKey.PublicKey) - if err != nil { - var pqErr *pq.Error - if errors.As(err, &pqErr) && pqErr.Constraint == "access_public_keys_pkey" { - return database.DuplicateError("public key already exists") - } - - return err - } - - return nil -} - -func (p *pgdb) AccessPublicKeyExists(ctx context.Context, publicKey *bfgd.AccessPublicKey) (bool, error) { - log.Tracef("AccessPublicKeyExists") - defer log.Tracef("AccessPublicKeyExists exit") - - const q = ` - SELECT EXISTS ( - SELECT * FROM access_public_keys WHERE public_key = $1 - ) - ` - - var exists bool - if err := p.db.QueryRowContext(ctx, q, publicKey.PublicKey).Scan(&exists); err != nil { - return false, err - } - - return exists, nil -} - -func (p *pgdb) AccessPublicKeyDelete(ctx context.Context, publicKey *bfgd.AccessPublicKey) error { - log.Tracef("AccessPublicKeyDelete") - defer log.Tracef("AccessPublicKeyDelete exit") - - const q = ` - DELETE FROM access_public_keys WHERE public_key = $1 - ` - - res, err := p.db.ExecContext(ctx, q, publicKey.PublicKey) - if err != nil { - return err - } - - rows, err := res.RowsAffected() - if err != nil { - return err - } - if rows == 0 { - return database.NotFoundError("public key not found") - } - - return nil -} - // BtcBlocksHeightsWithNoChildren returns the heights of blocks stored in the // database that do not have any children, these represent possible forks that // have not been handled yet. diff --git a/e2e/e2e_ext_test.go b/e2e/e2e_ext_test.go index d25699bb..bcfdcc04 100644 --- a/e2e/e2e_ext_test.go +++ b/e2e/e2e_ext_test.go @@ -284,7 +284,7 @@ func nextPort(ctx context.Context, t *testing.T) int { } } -func createBfgServerWithAuth(ctx context.Context, t *testing.T, pgUri string, electrsAddr string, btcStartHeight uint64, auth bool, otherBfgUrl string) (*bfg.Server, string, string, string) { +func createBfgServerGeneric(ctx context.Context, t *testing.T, pgUri string, electrsAddr string, btcStartHeight uint64, otherBfgUrl string) (*bfg.Server, string, string, string) { bfgPrivateListenAddress := fmt.Sprintf(":%d", nextPort(ctx, t)) bfgPublicListenAddress := fmt.Sprintf(":%d", nextPort(ctx, t)) @@ -294,7 +294,6 @@ func createBfgServerWithAuth(ctx context.Context, t *testing.T, pgUri string, el PgURI: pgUri, EXBTCAddress: electrsAddr, BTCStartHeight: btcStartHeight, - PublicKeyAuth: auth, RequestLimit: bfgapi.DefaultRequestLimit, RequestTimeout: bfgapi.DefaultRequestTimeout, BFGURL: otherBfgUrl, @@ -336,11 +335,11 @@ func createBfgServerWithAuth(ctx context.Context, t *testing.T, pgUri string, el } func createBfgServer(ctx context.Context, t *testing.T, pgUri string, electrsAddr string, btcStartHeight uint64) (*bfg.Server, string, string, string) { - return createBfgServerWithAuth(ctx, t, pgUri, electrsAddr, btcStartHeight, false, "") + return createBfgServerGeneric(ctx, t, pgUri, electrsAddr, btcStartHeight, "") } func createBfgServerConnectedToAnother(ctx context.Context, t *testing.T, pgUri string, electrsAddr string, btcStartHeight uint64, otherBfgUrl string) (*bfg.Server, string, string, string) { - return createBfgServerWithAuth(ctx, t, pgUri, electrsAddr, btcStartHeight, false, otherBfgUrl) + return createBfgServerGeneric(ctx, t, pgUri, electrsAddr, btcStartHeight, otherBfgUrl) } func createBssServer(ctx context.Context, t *testing.T, bfgWsurl string) (*bss.Server, string, string) { @@ -1188,107 +1187,6 @@ func TestBFGPublicErrorCases(t *testing.T) { } } -func TestBFGPrivateErrorCases(t *testing.T) { - type testTableItem struct { - name string - expectedError string - requests any - } - - testTable := []testTableItem{ - { - name: "public key create duplicate", - expectedError: "public key already exists", - requests: []bfgapi.AccessPublicKeyCreateRequest{ - { - PublicKey: hex.EncodeToString(privateKey.PubKey().SerializeCompressed()), - }, - { - PublicKey: hex.EncodeToString(privateKey.PubKey().SerializeCompressed()), - }, - }, - }, - { - name: "public key does not exist when deleting", - expectedError: "public key not found", - requests: []bfgapi.AccessPublicKeyDeleteRequest{ - { - PublicKey: hex.EncodeToString(privateKey.PubKey().SerializeCompressed()), - }, - }, - }, - { - name: "public key is invalid", - expectedError: "public key decode: encoding/hex: invalid byte: U+006C 'l'", - requests: []bfgapi.AccessPublicKeyCreateRequest{ - { - PublicKey: "blahblahblah", - }, - }, - }, - } - - for _, tti := range testTable { - t.Run(tti.name, func(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - ctx, cancel := defaultTestContext() - defer cancel() - - _, _, bfgPrivateWsUrl, _ := createBfgServer(ctx, t, pgUri, "", 1) - - c, _, err := websocket.Dial(ctx, bfgPrivateWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - assertPing(ctx, t, c, bfgapi.CmdPingRequest) - - bws := &bfgWs{ - conn: protocol.NewWSConn(c), - } - - requests := reflect.ValueOf(tti.requests) - for i := range requests.Len() { - req := requests.Index(i).Interface() - if err := bfgapi.Write(ctx, bws.conn, "someid", req); err != nil { - t.Fatal(err) - } - - _, _, response, err := bfgapi.Read(ctx, bws.conn) - if err != nil { - t.Fatal(err) - } - - // we only care about testing the final response, this allows - // us to test multiple and duplicate requests - if i != requests.Len()-1 { - continue - } - - switch v := response.(type) { - case *bfgapi.AccessPublicKeyCreateResponse: - if v.Error.Message != tti.expectedError { - t.Fatalf("%s != %s", v.Error.Message, tti.expectedError) - } - case *bfgapi.AccessPublicKeyDeleteResponse: - if v.Error.Message != tti.expectedError { - t.Fatalf("%s != %s", v.Error.Message, tti.expectedError) - } - default: - t.Fatalf("cannot determine type %T", v) - } - } - }) - } -} - func TestBitcoinInfo(t *testing.T) { db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) defer func() { @@ -3386,7 +3284,7 @@ func TestNotifyOnL2KeystonesBFGClientsViaOtherBFG(t *testing.T) { defer cancel() _, _, _, bfgPublicWsUrl := createBfgServer(ctx, t, pgUri, "", 1) - _, _, _, otherBfgPublicWsUrl := createBfgServerWithAuth(ctx, t, otherPgUri, "", 1, false, bfgPublicWsUrl) + _, _, _, otherBfgPublicWsUrl := createBfgServerGeneric(ctx, t, otherPgUri, "", 1, bfgPublicWsUrl) c, _, err := websocket.Dial(ctx, otherBfgPublicWsUrl, nil) if err != nil { @@ -3460,7 +3358,7 @@ func TestOtherBFGSavesL2KeystonesOnNotifications(t *testing.T) { defer cancel() _, _, _, bfgPublicWsUrl := createBfgServer(ctx, t, pgUri, "", 1) - _, _, _, otherBfgPublicWsUrl := createBfgServerWithAuth(ctx, t, otherPgUri, "", 1, false, bfgPublicWsUrl) + _, _, _, otherBfgPublicWsUrl := createBfgServerGeneric(ctx, t, otherPgUri, "", 1, bfgPublicWsUrl) c, _, err := websocket.Dial(ctx, otherBfgPublicWsUrl, nil) if err != nil { @@ -3865,483 +3763,6 @@ func TestNotifyMultipleBSSClients(t *testing.T) { wg.Wait() } -func TestBFGAuthNoKey(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - ctx, cancel := defaultTestContext() - defer cancel() - - if err := db.AccessPublicKeyInsert(ctx, &bfgd.AccessPublicKey{ - PublicKey: []byte("invalidkeyinvalidkeyinvalidkey111"), - }); err != nil { - t.Fatal(err) - } - - _, _, _, bfgPublicWsUrl := createBfgServerWithAuth(ctx, t, pgUri, "", 1, true, "") - - c, _, err := websocket.Dial(ctx, bfgPublicWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - var v interface{} - err = wsjson.Read(ctx, c, &v) - if err == nil { - t.Fatal("expecting error") - } -} - -func TestBFGAuthPing(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - ctx, cancel := defaultTestContext() - defer cancel() - - if err := db.AccessPublicKeyInsert(ctx, &bfgd.AccessPublicKey{ - PublicKey: privateKey.PubKey().SerializeCompressed(), - }); err != nil { - t.Fatal(err) - } - - _, _, _, bfgPublicWsUrl := createBfgServerWithAuth(ctx, t, pgUri, "", 1, true, "") - - c, _, err := websocket.Dial(ctx, bfgPublicWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - protocolConn := protocol.NewWSConn(c) - - if err := authClient.HandshakeClient(ctx, protocolConn); err != nil { - t.Fatal(err) - } - assertPing(ctx, t, c, bfgapi.CmdPingRequest) - - l2KeystonesRequest := bfgapi.L2KeystonesRequest{ - NumL2Keystones: 0, - } - - if err := bfgapi.Write(ctx, protocolConn, "someid", &l2KeystonesRequest); err != nil { - t.Fatal(err) - } - - command, id, _, err := bfgapi.Read(ctx, protocolConn) - if err != nil { - t.Fatal(err) - } - - if command != bfgapi.CmdL2KeystonesResponse { - t.Fatalf("incorrect command: %s", command) - } - - if id != "someid" { - t.Fatalf("incorrect id: %s", id) - } -} - -func TestBFGAuthPingThenRemoval(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - ctx, cancel := defaultTestContext() - defer cancel() - - if err := db.AccessPublicKeyInsert(ctx, &bfgd.AccessPublicKey{ - PublicKey: privateKey.PubKey().SerializeCompressed(), - }); err != nil { - t.Fatal(err) - } - - _, _, bfgWsPrivateUrl, bfgPublicWsUrl := createBfgServerWithAuth(ctx, t, pgUri, "", 1, true, "") - - c, _, err := websocket.Dial(ctx, bfgPublicWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - if err := authClient.HandshakeClient(ctx, protocol.NewWSConn(c)); err != nil { - t.Fatal(err) - } - assertPing(ctx, t, c, bfgapi.CmdPingRequest) - - privateC, _, err := websocket.Dial(ctx, bfgWsPrivateUrl, nil) - if err != nil { - t.Fatal(err) - } - defer privateC.CloseNow() - - bws := bfgWs{ - conn: protocol.NewWSConn(privateC), - } - - if err := bfgapi.Write(ctx, bws.conn, "someid", &bfgapi.AccessPublicKeyDeleteRequest{ - PublicKey: hex.EncodeToString(privateKey.PubKey().SerializeCompressed()), - }); err != nil { - t.Fatal(err) - } - - var v interface{} - err = wsjson.Read(ctx, c, &v) - if err != nil && !strings.Contains(err.Error(), "status = StatusProtocolError and reason = \"killed\"") { - t.Fatal(err) - } - - if err == nil { - t.Fatal("expecting error") - } -} - -func TestBFGAuthWrongKey(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - ctx, cancel := defaultTestContext() - defer cancel() - - if err := db.AccessPublicKeyInsert(ctx, &bfgd.AccessPublicKey{ - PublicKey: []byte("invalidkeyinvalidkeyinvalidkey111"), - }); err != nil { - t.Fatal(err) - } - - _, _, _, bfgPublicWsUrl := createBfgServerWithAuth(ctx, t, pgUri, "", 1, true, "") - - c, _, err := websocket.Dial(ctx, bfgPublicWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - if err := authClient.HandshakeClient(ctx, protocol.NewWSConn(c)); err != nil { - t.Fatal(err) - } - - var v interface{} - err = wsjson.Read(ctx, c, &v) - if err != nil && !strings.Contains(err.Error(), "status = StatusCode(4100)") { - t.Fatal(err) - } - - if err == nil { - t.Fatal("expecting error") - } -} - -func TestAddInvalidAccessPublicKey(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - ctx, cancel := defaultTestContext() - defer cancel() - - _, _, bfgPrivateWsUrl, _ := createBfgServer(ctx, t, pgUri, "", 1) - - c, _, err := websocket.Dial(ctx, bfgPrivateWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - bws := &bfgWs{ - conn: protocol.NewWSConn(c), - } - - assertPing(ctx, t, c, bfgapi.CmdPingRequest) - - if err := bfgapi.Write(ctx, bws.conn, "someid", &bfgapi.AccessPublicKeyCreateRequest{ - PublicKey: "nope", - }); err != nil { - t.Fatal(err) - } - - command, _, v, err := bfgapi.Read(ctx, bws.conn) - if err != nil { - t.Fatal(err) - } - - if command != bfgapi.CmdAccessPublicKeyCreateResponse { - t.Fatalf("unexpected command %s", command) - } - - resp := v.(*bfgapi.AccessPublicKeyCreateResponse) - if resp.Error == nil { - t.Fatal("expecting error") - } - - if !strings.Contains(resp.Error.String(), "encoding/hex: invalid byte") { - t.Fatalf("unexpected error %s", resp.Error) - } -} - -func TestDeleteInvalidAccessPublicKey(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - ctx, cancel := defaultTestContext() - defer cancel() - - _, _, bfgPrivateWsUrl, _ := createBfgServer(ctx, t, pgUri, "", 1) - - c, _, err := websocket.Dial(ctx, bfgPrivateWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - bws := &bfgWs{ - conn: protocol.NewWSConn(c), - } - - assertPing(ctx, t, c, bfgapi.CmdPingRequest) - - if err := bfgapi.Write(ctx, bws.conn, "someid", &bfgapi.AccessPublicKeyDeleteRequest{ - PublicKey: "nope", - }); err != nil { - t.Fatal(err) - } - - command, _, v, err := bfgapi.Read(ctx, bws.conn) - if err != nil { - t.Fatal(err) - } - - if command != bfgapi.CmdAccessPublicKeyDeleteResponse { - t.Fatalf("unexpected command %s", command) - } - - resp := v.(*bfgapi.AccessPublicKeyDeleteResponse) - if resp.Error == nil { - t.Fatal("expecting error") - } - - if !strings.Contains(resp.Error.String(), "encoding/hex: invalid byte") { - t.Fatalf("unexpected error %s", resp.Error) - } -} - -func TestAddDuplicateAccessPublicKey(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - privateKeyOne, err := dcrsecp256k1.GeneratePrivateKey() - if err != nil { - t.Fatal(err) - } - - publicKeyOne := hex.EncodeToString(privateKeyOne.PubKey().SerializeCompressed()) - - ctx, cancel := defaultTestContext() - defer cancel() - - _, _, bfgPrivateWsUrl, _ := createBfgServer(ctx, t, pgUri, "", 1) - - c, _, err := websocket.Dial(ctx, bfgPrivateWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - bws := &bfgWs{ - conn: protocol.NewWSConn(c), - } - - assertPing(ctx, t, c, bfgapi.CmdPingRequest) - - if err := bfgapi.Write(ctx, bws.conn, "someid", &bfgapi.AccessPublicKeyCreateRequest{ - PublicKey: publicKeyOne, - }); err != nil { - t.Fatal(err) - } - - command, _, v, err := bfgapi.Read(ctx, bws.conn) - if err != nil { - t.Fatal(err) - } - - if command != bfgapi.CmdAccessPublicKeyCreateResponse { - t.Fatalf("unexpected command %s", command) - } - - resp := v.(*bfgapi.AccessPublicKeyCreateResponse) - if resp.Error != nil { - t.Fatal(err) - } - - if err := bfgapi.Write(ctx, bws.conn, "someid", &bfgapi.AccessPublicKeyCreateRequest{ - PublicKey: publicKeyOne, - }); err != nil { - t.Fatal(err) - } - - command, _, v, err = bfgapi.Read(ctx, bws.conn) - if err != nil { - t.Fatal(err) - } - - if command != bfgapi.CmdAccessPublicKeyCreateResponse { - t.Fatalf("unexpected command %s", command) - } - - resp = v.(*bfgapi.AccessPublicKeyCreateResponse) - if resp.Error == nil { - t.Fatal("expecting error") - } -} - -func TestDeleteAccessPublicKeyThatDoesNotExist(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - privateKeyOne, err := dcrsecp256k1.GeneratePrivateKey() - if err != nil { - t.Fatal(err) - } - - publicKeyOne := hex.EncodeToString(privateKeyOne.PubKey().SerializeCompressed()) - - ctx, cancel := defaultTestContext() - defer cancel() - - _, _, bfgPrivateWsUrl, _ := createBfgServer(ctx, t, pgUri, "", 1) - - c, _, err := websocket.Dial(ctx, bfgPrivateWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - bws := &bfgWs{ - conn: protocol.NewWSConn(c), - } - - assertPing(ctx, t, c, bfgapi.CmdPingRequest) - - if err := bfgapi.Write(ctx, bws.conn, "someid", &bfgapi.AccessPublicKeyDeleteRequest{ - PublicKey: publicKeyOne, - }); err != nil { - t.Fatal(err) - } - - command, _, v, err := bfgapi.Read(ctx, bws.conn) - if err != nil { - t.Fatal(err) - } - - if command != bfgapi.CmdAccessPublicKeyDeleteResponse { - t.Fatalf("unexpected command %s", command) - } - - resp := v.(*bfgapi.AccessPublicKeyDeleteResponse) - if resp.Error == nil { - t.Fatal("expecting error") - } -} - -func TestDeleteAccessPublicKey(t *testing.T) { - db, pgUri, sdb, cleanup := createTestDB(context.Background(), t) - defer func() { - db.Close() - sdb.Close() - cleanup() - }() - - privateKeyOne, err := dcrsecp256k1.GeneratePrivateKey() - if err != nil { - t.Fatal(err) - } - - publicKeyOne := hex.EncodeToString(privateKeyOne.PubKey().SerializeCompressed()) - - ctx, cancel := defaultTestContext() - defer cancel() - - _, _, bfgPrivateWsUrl, _ := createBfgServer(ctx, t, pgUri, "", 1) - - c, _, err := websocket.Dial(ctx, bfgPrivateWsUrl, nil) - if err != nil { - t.Fatal(err) - } - defer c.CloseNow() - - bws := &bfgWs{ - conn: protocol.NewWSConn(c), - } - - assertPing(ctx, t, c, bfgapi.CmdPingRequest) - - if err := bfgapi.Write(ctx, bws.conn, "someid", &bfgapi.AccessPublicKeyCreateRequest{ - PublicKey: publicKeyOne, - }); err != nil { - t.Fatal(err) - } - - command, _, _, err := bfgapi.Read(ctx, bws.conn) - if err != nil { - t.Fatal(err) - } - - if command != bfgapi.CmdAccessPublicKeyCreateResponse { - t.Fatalf("unexpected command %s", command) - } - - if err := bfgapi.Write(ctx, bws.conn, "someid", &bfgapi.AccessPublicKeyDeleteRequest{ - PublicKey: publicKeyOne, - }); err != nil { - t.Fatal(err) - } - - command, _, v, err := bfgapi.Read(ctx, bws.conn) - if err != nil { - t.Fatal(err) - } - - if command != bfgapi.CmdAccessPublicKeyDeleteResponse { - t.Fatalf("unexpected command %s", command) - } - - resp := v.(*bfgapi.AccessPublicKeyDeleteResponse) - if resp.Error != nil { - t.Fatalf("unexpected error: %s", resp.Error.Message) - } -} - func createBtcBlock(ctx context.Context, t *testing.T, db bfgd.Database, count int, height int, lastHash []byte, l2BlockNumber uint32) bfgd.BtcBlock { header := make([]byte, 80) hash := make([]byte, 32) diff --git a/service/bfg/bfg.go b/service/bfg/bfg.go index 628a8520..ccb04e6f 100644 --- a/service/bfg/bfg.go +++ b/service/bfg/bfg.go @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Hemi Labs, Inc. +// Copyright (c) 2024-2025 Hemi Labs, Inc. // Use of this source code is governed by the MIT License, // which can be found in the LICENSE file. @@ -114,7 +114,6 @@ type Config struct { PrometheusListenAddress string PrometheusNamespace string PprofListenAddress string - PublicKeyAuth bool RequestLimit int RequestTimeout int // in seconds RemoteIPHeaders []string @@ -583,76 +582,6 @@ func (s *Server) handleBitcoinUTXOs(ctx context.Context, bur *bfgapi.BitcoinUTXO return buResp, nil } -func (s *Server) handleAccessPublicKeyCreateRequest(ctx context.Context, acpkc *bfgapi.AccessPublicKeyCreateRequest) (any, error) { - log.Tracef("handleAccessPublicKeyCreateRequest") - defer log.Tracef("handleAccessPublicKeyCreateRequest exit") - - publicKey, err := hex.DecodeString(acpkc.PublicKey) - if err != nil { - return &bfgapi.AccessPublicKeyCreateResponse{ - Error: protocol.RequestErrorf("public key decode: %v", err), - }, nil - } - - if err := s.db.AccessPublicKeyInsert(ctx, &bfgd.AccessPublicKey{ - PublicKey: publicKey, - }); err != nil { - if errors.Is(err, database.ErrDuplicate) { - return &bfgapi.AccessPublicKeyCreateResponse{ - Error: protocol.RequestErrorf("public key already exists"), - }, nil - } - - if errors.Is(err, database.ErrValidation) { - return &bfgapi.AccessPublicKeyCreateResponse{ - Error: protocol.RequestErrorf("invalid access public key"), - }, nil - } - - e := protocol.NewInternalErrorf("insert public key: %w", err) - return &bfgapi.AccessPublicKeyCreateResponse{ - Error: protocol.RequestErrorf("invalid access public key"), - }, e - } - - return &bfgapi.AccessPublicKeyCreateResponse{}, nil -} - -func (s *Server) handleAccessPublicKeyDelete(ctx context.Context, payload any) (any, error) { - log.Tracef("handleAccessPublicKeyDelete") - defer log.Tracef("handleAccessPublicKeyDelete exit") - - accessPublicKeyDeleteRequest, ok := payload.(*bfgapi.AccessPublicKeyDeleteRequest) - if !ok { - return nil, fmt.Errorf("incorrect type %T", payload) - } - - b, err := hex.DecodeString(accessPublicKeyDeleteRequest.PublicKey) - if err != nil { - return &bfgapi.AccessPublicKeyDeleteResponse{ - Error: protocol.RequestErrorf("public key decode: %v", err), - }, nil - } - - if err := s.db.AccessPublicKeyDelete(ctx, &bfgd.AccessPublicKey{ - PublicKey: b, - }); err != nil { - if errors.Is(err, database.ErrNotFound) { - // XXX not sure I like giving this information away. - return &bfgapi.AccessPublicKeyDeleteResponse{ - Error: protocol.RequestErrorf("public key not found"), - }, nil - } - e := protocol.NewInternalErrorf("error deleting access public key: %w", - err) - return &bfgapi.AccessPublicKeyDeleteResponse{ - Error: e.ProtocolError(), - }, e - } - - return &bfgapi.AccessPublicKeyDeleteResponse{}, nil -} - func (s *Server) processBitcoinBlock(ctx context.Context, height uint64) error { log.Tracef("Processing Bitcoin block at height %d...", height) @@ -921,20 +850,6 @@ func (s *Server) handleWebsocketPrivateRead(ctx context.Context, bws *bfgWs) { return s.handleBtcFinalityByKeystonesRequest(c, msg) } - go s.handleRequest(ctx, bws, id, cmd, handler) - case bfgapi.CmdAccessPublicKeyCreateRequest: - handler := func(c context.Context) (any, error) { - msg := payload.(*bfgapi.AccessPublicKeyCreateRequest) - return s.handleAccessPublicKeyCreateRequest(c, msg) - } - - go s.handleRequest(ctx, bws, id, cmd, handler) - case bfgapi.CmdAccessPublicKeyDeleteRequest: - handler := func(c context.Context) (any, error) { - msg := payload.(*bfgapi.AccessPublicKeyDeleteRequest) - return s.handleAccessPublicKeyDelete(c, msg) - } - go s.handleRequest(ctx, bws, id, cmd, handler) default: // Terminal error, exit. @@ -1177,25 +1092,6 @@ func (s *Server) handleWebsocketPublic(w http.ResponseWriter, r *http.Request) { userAgent = ua } - if s.cfg.PublicKeyAuth { - log.Tracef("will enforce auth") - - // XXX this code should be a function that returns just true - // and false; that function logs errors. - exists, err := s.db.AccessPublicKeyExists(hsCtx, &bfgd.AccessPublicKey{ - PublicKey: publicKey, - }) - if err != nil { - log.Errorf("error occurred checking if public key exists: %s", err) - return - } - if !exists { - log.Errorf("unauthorized public key: %s", publicKeyEncoded) - conn.Close(protocol.ErrPublicKeyAuth.Code, protocol.ErrPublicKeyAuth.Reason) - return - } - } - bws.publicKey = publicKey if bws.sessionId, err = s.newSession(bws); err != nil { log.Errorf("error occurred creating key: %s", err) From 4c699cfc25d8a58675fe99ffc3baffe5caae58b8 Mon Sep 17 00:00:00 2001 From: Marco Peereboom Date: Wed, 8 Jan 2025 11:36:09 +0000 Subject: [PATCH 2/2] Add v12 db --- database/bfgd/scripts/0012.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 database/bfgd/scripts/0012.sql diff --git a/database/bfgd/scripts/0012.sql b/database/bfgd/scripts/0012.sql new file mode 100644 index 00000000..832966ad --- /dev/null +++ b/database/bfgd/scripts/0012.sql @@ -0,0 +1,11 @@ +-- Copyright (c) 2025 Hemi Labs, Inc. +-- Use of this source code is governed by the MIT License, +-- which can be found in the LICENSE file. + +BEGIN; + +UPDATE version SET version = 12; + +DROP TABLE access_public_keys; + +COMMIT;