Skip to content

Commit fc3e997

Browse files
authored
feat: update pubkey check (#1462)
feat: update description
1 parent 2cf5543 commit fc3e997

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

modular/gater/auth_handler.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ func (g *GateModular) deleteUserPublicKeyV2Handler(w http.ResponseWriter, r *htt
442442
}
443443
if account != reqCtx.account {
444444
err = ErrNoPermission
445+
return
445446
}
446447

447448
data, err := io.ReadAll(r.Body)

modular/gater/auth_handler_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io"
99
"net/http"
1010
"net/http/httptest"
11+
"strings"
1112
"testing"
1213
"time"
1314

@@ -1164,3 +1165,98 @@ func TestListUserPublicKeyV2Handler(t *testing.T) {
11641165
})
11651166
}
11661167
}
1168+
1169+
// TestDeleteUserPublicKeyV2Handler_AccountMismatchBlocked verifies that a
1170+
// request whose ECDSA-recovered signer differs from X-Gnfd-User-Address is
1171+
// rejected and no keys are deleted.
1172+
func TestDeleteUserPublicKeyV2Handler_AccountMismatchBlocked(t *testing.T) {
1173+
ctrl := gomock.NewController(t)
1174+
defer ctrl.Finish()
1175+
1176+
signerKey, err := crypto.GenerateKey()
1177+
assert.NoError(t, err)
1178+
1179+
targetAddr := "0x1234567890AbcdEF1234567890aBcdef12345678"
1180+
1181+
req := httptest.NewRequest(http.MethodPost, "/auth/delete_keys_v2",
1182+
strings.NewReader("pubkey1,pubkey2"))
1183+
req.Header.Set(GnfdUserAddressHeader, targetAddr)
1184+
req.Header.Set(GnfdOffChainAuthAppDomainHeader, "https://test.com")
1185+
validExpiry := time.Now().Add(time.Hour).Format(ExpiryDateFormat)
1186+
req.Header.Set(commonhttp.HTTPHeaderExpiryTimestamp, validExpiry)
1187+
1188+
msgHash := commonhttp.GetMsgToSignInGNFD1Auth(req)
1189+
sig, err := crypto.Sign(msgHash, signerKey)
1190+
assert.NoError(t, err)
1191+
authHeader := fmt.Sprintf("%s,Signature=%s",
1192+
commonhttp.Gnfd1Ecdsa, hex.EncodeToString(sig))
1193+
req.Header.Set(GnfdAuthorizationHeader, authHeader)
1194+
1195+
mockedClient := gfspclient.NewMockGfSpClientAPI(ctrl)
1196+
mockedClient.EXPECT().DeleteAuthKeysV2(gomock.Any(), gomock.Any(),
1197+
gomock.Any(), gomock.Any()).Times(0)
1198+
1199+
gateway := &GateModular{
1200+
env: gfspapp.EnvLocal,
1201+
domain: testDomain,
1202+
}
1203+
gateway.baseApp = &gfspapp.GfSpBaseApp{}
1204+
gateway.baseApp.SetGfSpClient(mockedClient)
1205+
gateway.baseApp.SetOperatorAddress(TestSpAddress)
1206+
1207+
w := httptest.NewRecorder()
1208+
gateway.deleteUserPublicKeyV2Handler(w, req)
1209+
1210+
res := w.Result()
1211+
defer res.Body.Close()
1212+
data, _ := io.ReadAll(res.Body)
1213+
1214+
assert.Equal(t, http.StatusUnauthorized, res.StatusCode)
1215+
assert.Contains(t, string(data), "no permission")
1216+
}
1217+
1218+
// TestDeleteUserPublicKeyV2Handler_SameAccountSuccess verifies that a request
1219+
// whose signer matches X-Gnfd-User-Address succeeds normally.
1220+
func TestDeleteUserPublicKeyV2Handler_SameAccountSuccess(t *testing.T) {
1221+
ctrl := gomock.NewController(t)
1222+
defer ctrl.Finish()
1223+
1224+
userKey, err := crypto.GenerateKey()
1225+
assert.NoError(t, err)
1226+
userAddr := crypto.PubkeyToAddress(userKey.PublicKey)
1227+
1228+
req := httptest.NewRequest(http.MethodPost, "/auth/delete_keys_v2",
1229+
strings.NewReader("pubkey1,pubkey2"))
1230+
req.Header.Set(GnfdUserAddressHeader, userAddr.Hex())
1231+
req.Header.Set(GnfdOffChainAuthAppDomainHeader, "https://test.com")
1232+
validExpiry := time.Now().Add(time.Hour).Format(ExpiryDateFormat)
1233+
req.Header.Set(commonhttp.HTTPHeaderExpiryTimestamp, validExpiry)
1234+
1235+
msgHash := commonhttp.GetMsgToSignInGNFD1Auth(req)
1236+
sig, err := crypto.Sign(msgHash, userKey)
1237+
assert.NoError(t, err)
1238+
authHeader := fmt.Sprintf("%s,Signature=%s",
1239+
commonhttp.Gnfd1Ecdsa, hex.EncodeToString(sig))
1240+
req.Header.Set(GnfdAuthorizationHeader, authHeader)
1241+
1242+
mockedClient := gfspclient.NewMockGfSpClientAPI(ctrl)
1243+
mockedClient.EXPECT().DeleteAuthKeysV2(gomock.Any(), userAddr.Hex(),
1244+
"https://test.com", []string{"pubkey1", "pubkey2"}).
1245+
Return(true, nil).Times(1)
1246+
1247+
gateway := &GateModular{
1248+
env: gfspapp.EnvLocal,
1249+
domain: testDomain,
1250+
}
1251+
gateway.baseApp = &gfspapp.GfSpBaseApp{}
1252+
gateway.baseApp.SetGfSpClient(mockedClient)
1253+
gateway.baseApp.SetOperatorAddress(TestSpAddress)
1254+
1255+
w := httptest.NewRecorder()
1256+
gateway.deleteUserPublicKeyV2Handler(w, req)
1257+
1258+
res := w.Result()
1259+
defer res.Body.Close()
1260+
1261+
assert.Equal(t, http.StatusOK, res.StatusCode)
1262+
}

0 commit comments

Comments
 (0)