@ -0,0 +1,68 @@ |
|||
package api |
|||
|
|||
import ( |
|||
"errors" |
|||
"net/http" |
|||
"time" |
|||
|
|||
ethCommon "github.com/ethereum/go-ethereum/common" |
|||
"github.com/gin-gonic/gin" |
|||
"github.com/hermeznetwork/hermez-node/apitypes" |
|||
"github.com/hermeznetwork/hermez-node/common" |
|||
"github.com/iden3/go-iden3-crypto/babyjub" |
|||
) |
|||
|
|||
func postAccountCreationAuth(c *gin.Context) { |
|||
// Parse body
|
|||
var apiAuth receivedAuth |
|||
if err := c.ShouldBindJSON(&apiAuth); err != nil { |
|||
retBadReq(err, c) |
|||
return |
|||
} |
|||
// API to common + verify signature
|
|||
commonAuth := accountCreationAuthAPIToCommon(&apiAuth) |
|||
if !commonAuth.VerifySignature() { |
|||
retBadReq(errors.New("invalid signature"), c) |
|||
return |
|||
} |
|||
// Insert to DB
|
|||
if err := l2.AddAccountCreationAuth(commonAuth); err != nil { |
|||
retSQLErr(err, c) |
|||
return |
|||
} |
|||
// Return OK
|
|||
c.Status(http.StatusOK) |
|||
} |
|||
|
|||
func getAccountCreationAuth(c *gin.Context) { |
|||
// Get hezEthereumAddress
|
|||
addr, err := parseParamHezEthAddr(c) |
|||
if err != nil { |
|||
retBadReq(err, c) |
|||
return |
|||
} |
|||
// Fetch auth from l2DB
|
|||
auth, err := l2.GetAccountCreationAuthAPI(*addr) |
|||
if err != nil { |
|||
retSQLErr(err, c) |
|||
return |
|||
} |
|||
// Build succesfull response
|
|||
c.JSON(http.StatusOK, auth) |
|||
} |
|||
|
|||
type receivedAuth struct { |
|||
EthAddr apitypes.StrHezEthAddr `json:"hezEthereumAddress" binding:"required"` |
|||
BJJ apitypes.StrHezBJJ `json:"bjj" binding:"required"` |
|||
Signature apitypes.StrEthSignature `json:"signature" binding:"required"` |
|||
Timestamp time.Time `json:"timestamp"` |
|||
} |
|||
|
|||
func accountCreationAuthAPIToCommon(apiAuth *receivedAuth) *common.AccountCreationAuth { |
|||
return &common.AccountCreationAuth{ |
|||
EthAddr: ethCommon.Address(apiAuth.EthAddr), |
|||
BJJ: (*babyjub.PublicKey)(&apiAuth.BJJ), |
|||
Signature: []byte(apiAuth.Signature), |
|||
Timestamp: apiAuth.Timestamp, |
|||
} |
|||
} |
@ -0,0 +1,99 @@ |
|||
package api |
|||
|
|||
import ( |
|||
"bytes" |
|||
"encoding/hex" |
|||
"encoding/json" |
|||
"fmt" |
|||
"math/big" |
|||
"testing" |
|||
"time" |
|||
|
|||
ethCommon "github.com/ethereum/go-ethereum/common" |
|||
"github.com/hermeznetwork/hermez-node/common" |
|||
"github.com/stretchr/testify/assert" |
|||
) |
|||
|
|||
type testAuth struct { |
|||
EthAddr string `json:"hezEthereumAddress" binding:"required"` |
|||
BJJ string `json:"bjj" binding:"required"` |
|||
Signature string `json:"signature" binding:"required"` |
|||
Timestamp time.Time `json:"timestamp"` |
|||
} |
|||
|
|||
func genTestAuths(auths []*common.AccountCreationAuth) []testAuth { |
|||
testAuths := []testAuth{} |
|||
for _, auth := range auths { |
|||
testAuths = append(testAuths, testAuth{ |
|||
EthAddr: ethAddrToHez(auth.EthAddr), |
|||
BJJ: bjjToString(auth.BJJ), |
|||
Signature: "0x" + hex.EncodeToString(auth.Signature), |
|||
Timestamp: auth.Timestamp, |
|||
}) |
|||
} |
|||
return testAuths |
|||
} |
|||
|
|||
func TestAccountCreationAuth(t *testing.T) { |
|||
// POST
|
|||
endpoint := apiURL + "account-creation-authorization" |
|||
for _, auth := range tc.auths { |
|||
jsonAuthBytes, err := json.Marshal(auth) |
|||
assert.NoError(t, err) |
|||
jsonAuthReader := bytes.NewReader(jsonAuthBytes) |
|||
fmt.Println(string(jsonAuthBytes)) |
|||
assert.NoError( |
|||
t, doGoodReq( |
|||
"POST", |
|||
endpoint, |
|||
jsonAuthReader, nil, |
|||
), |
|||
) |
|||
} |
|||
// GET
|
|||
endpoint += "/" |
|||
for _, auth := range tc.auths { |
|||
fetchedAuth := testAuth{} |
|||
assert.NoError( |
|||
t, doGoodReq( |
|||
"GET", |
|||
endpoint+auth.EthAddr, |
|||
nil, &fetchedAuth, |
|||
), |
|||
) |
|||
assertAuth(t, auth, fetchedAuth) |
|||
} |
|||
// POST
|
|||
// 400
|
|||
// Wrong addr
|
|||
badAuth := tc.auths[0] |
|||
badAuth.EthAddr = ethAddrToHez(ethCommon.BigToAddress(big.NewInt(1))) |
|||
jsonAuthBytes, err := json.Marshal(badAuth) |
|||
assert.NoError(t, err) |
|||
jsonAuthReader := bytes.NewReader(jsonAuthBytes) |
|||
err = doBadReq("POST", endpoint, jsonAuthReader, 400) |
|||
assert.NoError(t, err) |
|||
// Wrong signature
|
|||
badAuth = tc.auths[0] |
|||
badAuth.Signature = badAuth.Signature[:len(badAuth.Signature)-1] |
|||
badAuth.Signature += "F" |
|||
jsonAuthBytes, err = json.Marshal(badAuth) |
|||
assert.NoError(t, err) |
|||
jsonAuthReader = bytes.NewReader(jsonAuthBytes) |
|||
err = doBadReq("POST", endpoint, jsonAuthReader, 400) |
|||
assert.NoError(t, err) |
|||
// GET
|
|||
// 400
|
|||
err = doBadReq("GET", endpoint+"hez:0xFooBar", nil, 400) |
|||
assert.NoError(t, err) |
|||
// 404
|
|||
err = doBadReq("GET", endpoint+"hez:0x0000000000000000000000000000000000000001", nil, 404) |
|||
assert.NoError(t, err) |
|||
} |
|||
|
|||
func assertAuth(t *testing.T, expected, actual testAuth) { |
|||
// timestamp should be very close to now
|
|||
assert.Less(t, time.Now().UTC().Unix()-3, actual.Timestamp.Unix()) |
|||
expected.Timestamp = actual.Timestamp |
|||
assert.Equal(t, expected, actual) |
|||
} |