You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The GatewayServer is a service that runs on a Gateway's infrastructure. It communicates with a wallet through HTTPS. Since Gateways are centralized, it makes no sense to use a decentralized communication protocol between Wallet<->Gateway.
Wallet needs an easy way to facilitate things like KYC/AML or registering the deposit account for user. GatewayServer makes it easy to integrate this process directly into the wallet.
Wallet
When the user is registering to the Gateway, the wallet reads the latest "Subscribe to Gateway" transaction. This transaction points user to the https://gateway.com/v1/details file that describes the plugin.
The plugin is also loaded every time the user opens a wallet. Wallet reads all PluginRegistered transactions and installs all plugins during runtime.
Plugin
A gateway's plugin is a lightweight json file that is pretty inflexible. The only actions that can be performed in the plugin are:
Registering the asset as a currency [ex. USD] plugin.
One-time greeting message.
Small messages in the footer, maybe some message list for that particular asset.
Adding buttons to the currency/asset, such as "Deposit", "Withdraw", "Perform KYC", "Change settings".
After the button is pressed, the user is presented with a form in a modal window. Modal window is a sandboxed iframe that is communicating directly with the Gateway.
GatewayServer
The GatewayServer serves as a middleware between a Wallet and a Gateway's internal workings. On the wallet side the GatewayServer will expose:
HTTPS Rest API, used for all of the communication with the Wallet.
iframes with forms presented to the user.
I propose that we write the GatewayServer in Python.
It's a very popular language, definitely more popular than Scala.
It's extremely easy to extend. GatewayServer can be configured so that just dropping a folder inside a GatewayServer extends it's functionality.
Python is my favorite language. It has a sexy syntax. :-P
Though Java is also ok due to it's unparalleled popularity.
Off-chain communication API:
Secure Limited Markdown
A stripped version of Markdown that is secure against XSS attacks.
Sandboxed iframe
Forms&messages displayed by Gateways are presented in the form of iframe modal windows. Every time a user clicks a Gateway-specific button, a modal window with an iframe is loaded.
IFrame communicates with the wallet through postMessage API.
Messages
Do we need a centralized messaging system? Should we ask a Gateway periodically if it has some messages to display to the user?
This is an anonymity breach IMO [Gateway knows when the user opens/closes his wallet every time], that's why I'm reluctant to include this...
It can be implemented later if it's needed.
Authentication challenge
We need for the client to be able to reliably authenticate itself with the GatewayServer.
This method must:
Use existing keys from the blockchain.
Be resistant to key-repetition attack.
Preferably it shouldn't need any authentication.
We don't want Gateway to spy on it's clients. That's why the wallet needs to cache it's buttons by default and ask for changes only when a button is pressed.
GatewayServer<->Wallet API:
Every message between Gateway<-->Wallet is encrypted with HTTPS and it's additionally signed with Curve25519 of the issuer and Wallet.
Thus, MITM with a spoofed HTTPS key [NSA] can only read communication from&to Gateway, it cannot spoof it. To spoof such communication requires a GAC_private_key to become compromised.
Wallet Authentication Challenge - WAC headers
To authenticate itself to the GatewayServer, the Wallet uses HTTP header parameters. The parameters are as follows:
"asset_id": "FYNEWP6uuaM53hCHuJzj8dw2zamoipokZpKQLNFZLVmP", # GatewayServer's asset ID
"public_key": "FkoFqtAeibv2E6Y86ZDRfAkZz61LwUMjLAP2gmS1j7xe", # Wallet's address public key - Base58
"gateway_public_key": "zkweWR234SZFzbiorj5t5BFCBOetepo4gkdbzZA2342a",
"timestamp": 192831989048, # Unix time with millisecond resolution
"auth_hash": "Blake2b256 hash" # MAC that authenticates the message and the wallet
gateway_public_key is the public key taken from the GAC_private_key. It's the same key that is published on the blockchain with "Asset details" transaction.
Auth_hash is calculated as follows: blake2b256(asset_id(256bit)+public_key(256bit)+timestamp(64bit)+CONTENT)
We're protecting ourselves against replay attacks by having GatewayServer accept only newer timestamps. If wallet_nonce.timestamp <= last_known_timestamp or auth_hash is incorrect, GatewayServer ignores the request.
Ajax API
Every message is GAC and WAC protected.
Description Call: GET - /v1/details
WAC_headers
Response:
{
"description": "This is a super duper BTC Gateway! Please enter <KYC> to continue.",
"icon": "https://gateway.com/icon.png",
"version": 1,
"interactive": true
}
"description" - this is an asset description. It's shown when the user clicks on an asset. 100kB is the limit. It's a Secure Limited Markdown.
"version" - API version supported by the GatewayServer. The wallet will use the newest version it understands.
"interactive" - This call informs the Wallet if this is a static .json file [false], or is it a live GatewayServer [true]. If it's a live GatewayServer, the wallet will continue interaction with GatewayServer with the API's below.
"icon" - Small icon representing the asset. Everyone loves icons.
The description is shown when the user is presented with an asset in a wallet. It's a greeting from an asset issuer describing the asset and what it does.
"subscribe_to_gateway_timestamp" - Timestamp for "Subscribe to Gateway" transaction. Optional.
"subscribe_to_gateway_recipient_signature" - Recipient signature for "Subscribe to Gateway" transaction. Optional.
Response:
{
"greeting": "greeting",
"asset_details_message": "SecureMarkdown",
"buttons": [
{
"name": "KYC",
"description": "To start using this gateway you must first fill the KYC",
"iframe": "kyc",
"main_page": 1
},
{
"name": "Deposit",
"description": "Deposit money to the gateway",
"iframe": "deposit"
"main_page": 2
},
{
"name": "Withdraw",
"description": "Withdraw money from the gateway",
"iframe": "withdraw"
"main_page": 3
},
{
"name": "Convert",
"description": "Convert money from one currency to the other",
"iframe": "convert"
},
{
"name": "Loan",
"description": "Fill a form and take a loan",
"iframe": "loan"
}
]
}
"greeting" - optional - Presents a greeting from the Gateway [iframe modal] just after the asset is registered. The iframe points to "{$asset_details_tx_url}/v1/forms/{$greeting}" specifically.
"asset_details_message" - optional - A Secure Markdown message that is displayed on "Asset Details" page, just below asset_id, balance and whatnot info.
"buttons" - Buttons that are displayed on "Assetransferred to his "Assets" page. The Asset is displayed t Details" page in the Wallet. The buttons are ordered as they appear in the "Asset Details" page.
"name" - Name of the button. Should be short [< 16 chars], preferably one word.
"description" - Short description of a button.
"main_page" - optional, int - Should the button be displayed on the main page of the wallet? [As one of up to 3 default buttons - 1 - left, 2 - center, 3 - right]
"iframe" - The iframe points to "{$asset_details_tx_url}/v1/forms/{$iframe}" specifically.
This call is used to register the Wallet with the Gateway. This method is called when the user accepts the asset. The "Subscribe to gateway" transaction can be sent by the Gateway if the Wallet wants it to.
Form Call: iframe - /v1/forms/$form_name?WAC_headers
These calls will be done through iframes, so we have to rely on GET method to carry WAC headers.
Response:
A web page from the Gateway containing the particular form.
A form call should contain some logic for communicating with the Wallet [through postMessage]. The iframe at least needs to inform when it should be closed...
Form<-->Wallet API:
I'm not familiar with postMessage capabilities, so this part will be less detailed.
The messages we need include:
Close the modal window
Ask the Gateway again for Buttons
Blockchain transactions:
Asset details
SPEC: [sender, asset_id, GatewayServer_api_URL, GAC_public_key, sender_signature]
This transaction is sent by an address that issued or has owner rights to the asset. It specifies the API of the GatewayServer of particular asset.
It can be pointed to a static .json file for assets that just want a fancy description, but don't need any of the GatewayServer's features.
GatewayServer_api_URL. If the URL doesn't start with "https://", the transaction is invalid. if sender.is_an_issuer(asset_id): transaction_is_not_valid
Only the newest Asset details transaction is taken into account when wallet engages the Gateway, all older ones are ignored. This transaction can be prunable.
GAC_public_key is a key that is used by the Wallet to make sure that it's really talking to the Gateway. It's different from an issuer account public key because it's impossible to keep this key in cold storage - GAC_public_key has to be running on a live server 24/7, thus it's exposed to compromise.
Transfer asset issuer rights
SPEC: [sender, recipient, asset_id, sender_signature]
This transaction transfers privileges of an asset issuer [ex. Asset Details Transaction] to a new account.
After this transaction is made, the old "Asset details transaction" is still valid until the newer one is generated. [Even though it's on an older account]
Subscribe to Gateway
SPEC: [sender, recipient, asset_id, sender_signature, recipient_signature]
This transaction informs the Wallet that it's subscribed to the particular gateway.
For user's convenience the Gateway pays the transaction fee. The user may have 0 Waves in his account right now.
Unsubscribe from the Gateway
SPEC: [sender, asset_id, sender_signature]
The user experience:
ITB - In the background
User clicks on the asset of the gateway [for example through the link from the Gateway's website: waves://assets/18731273194817823713].
The user is greeted with an asset page, pretty similar to NXT's asset pages.
ITB - 0.5s: Wallet requests Asset Details transaction from the node.
ITB - 0.5s: Wallet requests Description Call from the Gateway.
ITB - 0.5s: Wallet parses Secure Limited Markdown. Wallet downloads all prerequisite images.
The user is presented with a full-fledged asset description with logos and whatnot.
The user clicks on "Register asset" button.
ITB - 0.5s: Wallet requests "Register Call".
ITB - 0.5s: Wallet opens a modal with an iframe with "greetingskyc" form.
The user is presented with a greeting&KYC form.
The user fills his KYC form.
ITB - Iframe sends a postMessage to the Wallet - close the iframe & resend register call
The iframe closes.
ITB - 0.5s: Wallet requests "Register Call" from the Gateway.
User is presented with new buttons.
User clicks on a "Deposit" button.
...
It is also possible to make a live help chat through iframes with the Gateway.
Things to consider:
Maybe we should ask Gateway for "Register Call" every time? The Wallet may be waiting for KYC confirmation for example...
The text was updated successfully, but these errors were encountered:
The GatewayServer is a service that runs on a Gateway's infrastructure. It communicates with a wallet through HTTPS. Since Gateways are centralized, it makes no sense to use a decentralized communication protocol between Wallet<->Gateway.
Wallet needs an easy way to facilitate things like KYC/AML or registering the deposit account for user. GatewayServer makes it easy to integrate this process directly into the wallet.
Wallet
When the user is registering to the Gateway, the wallet reads the latest "Subscribe to Gateway" transaction. This transaction points user to the https://gateway.com/v1/details file that describes the plugin.
The plugin is also loaded every time the user opens a wallet. Wallet reads all PluginRegistered transactions and installs all plugins during runtime.
Plugin
A gateway's plugin is a lightweight json file that is pretty inflexible. The only actions that can be performed in the plugin are:
After the button is pressed, the user is presented with a form in a modal window. Modal window is a sandboxed iframe that is communicating directly with the Gateway.
GatewayServer
The GatewayServer serves as a middleware between a Wallet and a Gateway's internal workings. On the wallet side the GatewayServer will expose:
I propose that we write the GatewayServer in Python.
Though Java is also ok due to it's unparalleled popularity.
Off-chain communication API:
Secure Limited Markdown
A stripped version of Markdown that is secure against XSS attacks.
Sandboxed iframe
Forms&messages displayed by Gateways are presented in the form of iframe modal windows. Every time a user clicks a Gateway-specific button, a modal window with an iframe is loaded.
IFrame communicates with the wallet through postMessage API.
Messages
Do we need a centralized messaging system? Should we ask a Gateway periodically if it has some messages to display to the user?
This is an anonymity breach IMO [Gateway knows when the user opens/closes his wallet every time], that's why I'm reluctant to include this...
It can be implemented later if it's needed.
Authentication challenge
We need for the client to be able to reliably authenticate itself with the GatewayServer.
This method must:
We don't want Gateway to spy on it's clients. That's why the wallet needs to cache it's buttons by default and ask for changes only when a button is pressed.
GatewayServer<->Wallet API:
Every message between Gateway<-->Wallet is encrypted with HTTPS and it's additionally signed with Curve25519 of the issuer and Wallet.
Thus, MITM with a spoofed HTTPS key [NSA] can only read communication from&to Gateway, it cannot spoof it. To spoof such communication requires a GAC_private_key to become compromised.
Wallet Authentication Challenge - WAC headers
To authenticate itself to the GatewayServer, the Wallet uses HTTP header parameters. The parameters are as follows:
gateway_public_key is the public key taken from the GAC_private_key. It's the same key that is published on the blockchain with "Asset details" transaction.
Auth_hash is calculated as follows:
blake2b256(asset_id(256bit)+public_key(256bit)+timestamp(64bit)+CONTENT)
We're protecting ourselves against replay attacks by having GatewayServer accept only newer timestamps. If
wallet_nonce.timestamp <= last_known_timestamp
orauth_hash is incorrect
, GatewayServer ignores the request.Ajax API
Every message is GAC and WAC protected.
Description Call: GET - /v1/details
WAC_headers
Response:
"description" - this is an asset description. It's shown when the user clicks on an asset. 100kB is the limit. It's a Secure Limited Markdown.
"version" - API version supported by the GatewayServer. The wallet will use the newest version it understands.
"interactive" - This call informs the Wallet if this is a static .json file [false], or is it a live GatewayServer [true]. If it's a live GatewayServer, the wallet will continue interaction with GatewayServer with the API's below.
"icon" - Small icon representing the asset. Everyone loves icons.
The description is shown when the user is presented with an asset in a wallet. It's a greeting from an asset issuer describing the asset and what it does.
Register Call: POST - /v1/register/
WAC_headers
Request:
"subscribe_to_gateway_timestamp" - Timestamp for "Subscribe to Gateway" transaction. Optional.
"subscribe_to_gateway_recipient_signature" - Recipient signature for "Subscribe to Gateway" transaction. Optional.
Response:
"greeting" - optional - Presents a greeting from the Gateway [iframe modal] just after the asset is registered. The iframe points to "{$asset_details_tx_url}/v1/forms/{$greeting}" specifically.
"asset_details_message" - optional - A Secure Markdown message that is displayed on "Asset Details" page, just below asset_id, balance and whatnot info.
"buttons" - Buttons that are displayed on "Assetransferred to his "Assets" page. The Asset is displayed t Details" page in the Wallet. The buttons are ordered as they appear in the "Asset Details" page.
"name" - Name of the button. Should be short [< 16 chars], preferably one word.
"description" - Short description of a button.
"main_page" - optional, int - Should the button be displayed on the main page of the wallet? [As one of up to 3 default buttons - 1 - left, 2 - center, 3 - right]
"iframe" - The iframe points to "{$asset_details_tx_url}/v1/forms/{$iframe}" specifically.
This call is used to register the Wallet with the Gateway. This method is called when the user accepts the asset. The "Subscribe to gateway" transaction can be sent by the Gateway if the Wallet wants it to.
Form Call: iframe - /v1/forms/$form_name?WAC_headers
These calls will be done through iframes, so we have to rely on GET method to carry WAC headers.
Response:
A web page from the Gateway containing the particular form.
A form call should contain some logic for communicating with the Wallet [through postMessage]. The iframe at least needs to inform when it should be closed...
Form<-->Wallet API:
I'm not familiar with postMessage capabilities, so this part will be less detailed.
The messages we need include:
Blockchain transactions:
Asset details
SPEC: [sender, asset_id, GatewayServer_api_URL, GAC_public_key, sender_signature]
This transaction is sent by an address that issued or has owner rights to the asset. It specifies the API of the GatewayServer of particular asset.
It can be pointed to a static .json file for assets that just want a fancy description, but don't need any of the GatewayServer's features.
GatewayServer_api_URL. If the URL doesn't start with "https://", the transaction is invalid.
if sender.is_an_issuer(asset_id): transaction_is_not_valid
Only the newest
Asset details transaction
is taken into account when wallet engages the Gateway, all older ones are ignored. This transaction can be prunable.GAC_public_key is a key that is used by the Wallet to make sure that it's really talking to the Gateway. It's different from an issuer account public key because it's impossible to keep this key in cold storage - GAC_public_key has to be running on a live server 24/7, thus it's exposed to compromise.
Transfer asset issuer rights
SPEC: [sender, recipient, asset_id, sender_signature]
This transaction transfers privileges of an asset issuer [ex. Asset Details Transaction] to a new account.
After this transaction is made, the old "Asset details transaction" is still valid until the newer one is generated. [Even though it's on an older account]
Subscribe to Gateway
SPEC: [sender, recipient, asset_id, sender_signature, recipient_signature]
This transaction informs the Wallet that it's subscribed to the particular gateway.
For user's convenience the Gateway pays the transaction fee. The user may have 0 Waves in his account right now.
Unsubscribe from the Gateway
SPEC: [sender, asset_id, sender_signature]
The user experience:
ITB - In the background
ITB - 0.5s: Wallet requests Asset Details transaction from the node.
ITB - 0.5s: Wallet requests Description Call from the Gateway.
ITB - 0.5s: Wallet parses Secure Limited Markdown. Wallet downloads all prerequisite images.
ITB - 0.5s: Wallet requests "Register Call".
ITB - 0.5s: Wallet opens a modal with an iframe with "greetingskyc" form.
ITB - Iframe sends a postMessage to the Wallet - close the iframe & resend register call
ITB - 0.5s: Wallet requests "Register Call" from the Gateway.
...
It is also possible to make a live help chat through iframes with the Gateway.
Things to consider:
Maybe we should ask Gateway for "Register Call" every time? The Wallet may be waiting for KYC confirmation for example...
The text was updated successfully, but these errors were encountered: