|
8 | 8 | "io" |
9 | 9 | "net/http" |
10 | 10 | "net/http/httptest" |
| 11 | + "strings" |
11 | 12 | "testing" |
12 | 13 | "time" |
13 | 14 |
|
@@ -1164,3 +1165,98 @@ func TestListUserPublicKeyV2Handler(t *testing.T) { |
1164 | 1165 | }) |
1165 | 1166 | } |
1166 | 1167 | } |
| 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