Add Mercuryo signer to proxy
Description
We're currently hardcoding credentials in status-go that are used to generate a signature for Mercuryo URLs. For safety reasons, these should be hidden in our proxy, and the signature should be generated through an http request.
Specs: https://www.notion.so/Mercuryo-de1bd29b77054f4b865c8cba997bd490
Why was that done in the first place? This means these signatures are already leaked.
Is it possible to rotate those?
@jakubgs
Why was that done in the first place? quickest way of making mercuryo work
This means these signatures are already leaked the signature only allows you to create a URL with our widget-id, they cannot access our account or consume rate limits or anything like that.
Is it possible to rotate those? yes, I'm planning to do that as soon as we've got a proxy signer. you can just change the secret key or create a new "widget" in our account
So how is this supposed to work? Can you explain in more detail what paths you expect to be proxied? And how are credentials passed?
hmm I'm thinking of:
- We link the user to something like
https://prod.api.status.im/mercuryo/?address={address}&(other parameters) - Then the proxy does a redirect appending the widget ID and its corresponding signature:
https://exchange.mercuryo.io/?address={address}&(other parameters)&widget_id={widget-id}&signature={signature}The signature needs to be generated in the proxy using the logic that's currently in status-go (that is, SHA512 of the stringAddressSecret). The Secret and the WidgetID need to be baked into the proxy like we currently bake provider API keys, that way we can freely rotate the two of them if we wish to.
Example:
User gets linked to:
https://prod.api.status.im/mercuryo/?type=buy&network=ETHEREUM¤cy=ETH&address=0x0ADB6CaA256A5375C638C00e2fF80A9Ac1b2d3A7&hide_address=false&fix_address=true
We redirect them to:
https://exchange.mercuryo.io/?type=buy&network=ETHEREUM¤cy=ETH&address=0x0ADB6CaA256A5375C638C00e2fF80A9Ac1b2d3A7&hide_address=false&fix_address=true&signature=817cf6a1461e42d676bbb0feae6fdb52c3c58d334ba0ab0001db5b2e897b7584f1adcad6bd385fb39e792178665803f63dd39cf3a4ece4d51dc2f106eef1b77b&widget_id=6a7eb330-2b09-49b7-8fd3-1c77cfb6cd47
Does that sound reasonable? If it does, I'll write proper requirements in Notion.
The implementation seems pretty trivial:
// Should generate the SHA512 hash of the string "AddressKey"
func getMercuryoSignature(address common.Address, key string) string {
addressString := address.Hex()
hash := sha512.New()
hash.Write([]byte(addressString[:] + key))
return fmt.Sprintf("%x", hash.Sum(nil))
}
https://github.com/status-im/status-go/blob/e07182b3f36731a7e0dbf6ec59b28f0df56d6a43/services/wallet/onramp/provider_mercuryo.go#L105-L112
So it should be doable in Lua. But would we prefer to proxy requests or redirect them?
Legal says we shouldn't link the user to a .status.im website in any part of the process, so we need to get the signature from the proxy and build the URL in the client.
Added doc with specs to the description
This can be done by implementing this Lua script to proxy hosts:
local _M = {}
local cjson = require "cjson.safe"
local sha512 = require "resty.sha512"
local resty_string = require "resty.string"
-- Access Mercuryo constants from Nginx variables
local widget_id = ngx.var.widget_id
local widget_secret = ngx.var.widget_secret
-- Function to generate SHA512 signature
local function getMercuryoSignature(address, key)
local hash = sha512:new()
if not hash then
ngx.log(ngx.ERR, "Failed to create SHA512 object")
return nil
end
hash:update(address .. key) -- Concatenate the address and key (widget_secret)
local digest = hash:final()
return resty_string.to_hex(digest)
end
-- Function to process incoming requests
function _M.process_request()
-- Get the 'address' query parameter
local address = ngx.var.arg_address -- Retrieve the address from the query parameters
-- Ensure the address is present
if not address then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.say(cjson.encode({ error = "Missing address query parameter" }))
return ngx.exit(ngx.HTTP_BAD_REQUEST)
end
-- Generate the signature
local signature = getMercuryoSignature(address, widget_secret)
if signature then
-- Send the response with widget_id and generated signature
ngx.say(cjson.encode({ widget_id = widget_id, signature = signature }))
return ngx.exit(ngx.HTTP_OK)
else
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.say(cjson.encode({ error = "Failed to generate signature" }))
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
end
return _M
which by curl to proxy server:
curl -s https://test.api.status.im/mercuryo/sign/?address=0xXXXXXXXxxxxXxXXX-u $USER:$PASS
returns:
{"widget_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx","signature":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
@dlipicar this is done on both test and prod. Let me know if anything needs to be modified.
@dlipicar unless you have any objections I'm closing this as done.