ASPX / VB-Code-Behind API port


#1

Hey again,

Here is some dirty, dirty code to enable ETN Instant Payment API confirmation in an ASPX / VB environment.

The ASPX is the front end client-side code (the stuff the customer sees)
The Visual Basic does all the grunt-work on the server, updating value etc.

NOTES:
The VB code can quite easily be converted into C# by anyone who understands / prefers that language. I don’t use it myself, even though I admit its superior.

The ASPX code is designed to use a Site.Master layout template. You will need to point this to your own master, or remove it if you do not use one.

The ASPX code points to ‘Webapplication3’ as a project name, change this to match your own project.

Yes, my code is ugly and probably the worst way to go about things. But hey, I started learning these languages two weeks ago.

ETNpayment.aspx

<%@ Page Title="Payment: Electroneum" Language="vb" AutoEventWireup="false" MasterPageFile="~/Site.Master" CodeBehind="ETNpayment.aspx.vb" Inherits="WebApplication3.ETNpayment" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    
    <%--
        Welcome,

        This page is currently set in a site.master template.
        You will need to change the above header MasterPageFile="~/Site.Master"  to point at your own master template
        as well as changing:    Inherits="WebApplication3.ETNpayment"   to point at your own solution/page name.

        Below I create text boxes in this order:

        Total sale cost + shipping fee
        Current ETN exchange rate
        ETN cost of sale
        ETN transfer fee (currently 5 etn?)
        ETN cost of sale + transfer fee total

        Then:

        A QR CODE from Electroneum, which our VB code-behind passes info into

        A Time out textbox, which our code-behind updates. Default = 300 seconds (5 minutes)

        A hidden timer function that counts down from a code-behind defined number of seconds (set as 300), the interval = 1000 (milliseconds)

        A button to return the user to the payment-gateway, if they change their mind about how they wanted to pay.

        --%>

      <br />
    <h2><%: Title %></h2>
    <br />
    <asp:TextBox ID="TextBox1" runat="server" Width="200px" ReadOnly="True" BorderStyle="None" Font-Bold="True">Total Sale Cost + Shipping: </asp:TextBox> <asp:TextBox ID="Salecostshipping" runat="server" Width="200px" BorderStyle="None"></asp:TextBox>
    <br />
     <asp:TextBox ID="TextBox3" runat="server" Width="200px" BorderStyle="None" Font-Bold="True">ETN Exchange Range: </asp:TextBox> <asp:TextBox ID="ETNexchangerate" runat="server" Width="200px" BorderStyle="None"></asp:TextBox>
      <br />
       <asp:TextBox ID="TextBox5" runat="server" Width="200px" ReadOnly="True" BorderStyle="None" Font-Bold="True">ETN Cost:</asp:TextBox> <asp:TextBox ID="ETNcost" runat="server" Width="200px" BorderStyle="None"></asp:TextBox>
      <br />
      <asp:TextBox ID="TextBox2" runat="server" Width="200px" ReadOnly="True" BorderStyle="None" Font-Bold="True">+ Transfer Fee:</asp:TextBox> <asp:TextBox ID="ETNtransferfee" runat="server" Width="200px" BorderStyle="None"></asp:TextBox>
      <br />
      <asp:TextBox ID="TextBox4" runat="server" Width="200px" ReadOnly="True" BorderStyle="None" Font-Italic="False" Font-Bold="True">Total ETN Cost:</asp:TextBox> <asp:TextBox ID="ETNtotalcost" runat="server" Width="200px" Font-Bold="True" BorderStyle="None" ReadOnly="True"></asp:TextBox>
      <br />
      <br />
      <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
    <script src="Scripts/etn.vendor-widget.js"></script>
<div id="etnqrcode" runat="server" data-etn-vendor="" data-etn-lang="en"></div>
      <br />
      <br />
         <asp:UpdatePanel ID="UpdatePanel1" runat="server">
  <ContentTemplate>
       <asp:TextBox ID="Timeout" runat="server" Width="200px" Text="Timeout in 300 seconds." ReadOnly="True"></asp:TextBox> 
   <asp:Timer runat="server" ID="Timer1"  ontick="Begincheck" interval="1000"  ValidateRequestMode="Disabled" EnableViewState="False" ViewStateMode="Disabled" />
       <br>
      </br>
          <asp:Button ID="Back" runat="server"  OnClick="Back_Click" Text="Cancel Payment" /> 

  </ContentTemplate>
</asp:UpdatePanel>

</asp:Content>

ETNpayment.aspx.vb

Imports System.Data.SqlClient
Imports System.IO
Imports System.Net
Imports System.Security.Cryptography
Imports System.Web.Script.Serialization
' IMPORTANT - DOWNLOAD THIS NUTGET PACKAGE / IMPORT IT AS IT ENABLES JSON'
Imports Newtonsoft.Json
'///////////////////////

Public Class ETNpayment
    Inherits System.Web.UI.Page
    Public currency, etnwallett, etnsecret As String 'Pretty self explainatory
    Public pricestring ' total price of all cart items + shipping
    Public qrgenerator  ' a place to hold my generated QR code string
    Public saleid As String      ' sale ID, before padding
    Public ETNCOSTBEFORETX ' If you want to show price before TX fee added
    Public EXCHANGEPRICE   ' current ETN exchange price for local currency
    Public ETNTXFEE        '  Set the ETN Transfer Fee (Approx 5 ETN?)
    Public TOTALETNCOST    ' The grand total. This is what we charge the user
    Public saleidstring As String ' the padded sale id  to pass to ETN QR code
    Public serializedResult As String  ' Our JSON serializer
    Public status            ' What status is our ETN payment? 0 = fail, 1 = pass
    Public counter As Integer ' Timeout counter
    Public newcount            ' updates for Timeout counter


    '//////////// 
    ' A simple back button to return to the payment gateway if user incorrectly selected Electroneum
    '////////////
    Protected Sub Back_Click(sender As Object, e As EventArgs)
        Response.Redirect("Paymentgateway.aspx")
    End Sub


    '//////////////////
    ' MAIN SUB ROUTINE!!!
    '//////////////////
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        ' get initial varialbes. I pull these from a database, its up to you to figure out how to pass them into this page.
        currency = "USD" ' currency (USD, AUS, NZD etc), as string - CAPITALS!!
        etnwallett = "etn-it-12345667890" ' your wallet string (etn-it-xxxxxxx), as string
        etnsecret = "secret_stuff_goes_here"   'your ETN secret, as string
        saleid = "0000000001"  'your sale id, as string, doesnt have to be 10 digits as the code below pads it!
        saleidstring = "0000000000".Substring(0, Math.Max(0, 10 - saleid.ToString.Length)) & saleid.ToString  ' pad the sale ID to 10 digits!!!!
        pricestring = "1.00"  '  = the initial sale price - including shipping costs if any, as string. should not be 0.00

        getetnvalue()  ' Loads the JSON files to get current ETN price

        ' Load up the onscreen texts
        Salecostshipping.Text = "$" + pricestring.ToString
        ETNexchangerate.Text = EXCHANGEPRICE.ToString
        ETNcost.Text = (Math.Round(ETNCOSTBEFORETX, 2, MidpointRounding.AwayFromZero)).ToString  ' rounding to 2 decimal places
        ETNtransferfee.Text = (Math.Round(ETNTXFEE, 2, MidpointRounding.AwayFromZero)).ToString
        ETNtotalcost.Text = (Math.Round(TOTALETNCOST, 2, MidpointRounding.AwayFromZero)).ToString

        Dim stringtheory As String = (etnwallett & "/" & saleidstring & "/").ToString  ' This generates our QR code!! VERY IMPORTANT
        qrgenerator = stringtheory & Decimal.Parse(Math.Round(TOTALETNCOST, 2, MidpointRounding.AwayFromZero)) ' This too!
        etnqrcode.Attributes.Add("data-etn-vendor", qrgenerator)  ' Sets my QR code in the DIV block

    End Sub


    '////////////////////////
    ' This sub gets our ETN exchange rates and determines local currency to ETN conversion
    '////////////////////////
    ' No need to change?!
    Sub getetnvalue()
        Dim contents As String
        Using wc As New System.Net.WebClient

            contents = wc.DownloadString(New Uri("https://supply.electroneum.com/app-value-v2.json"))  ' Downloads the current ETN prices from Electroneum.com

        End Using

        ' Finding the local price by splitting the strings. Im sure theres a better way, but im lazy.
        Dim etnpricesplit = Split(contents, "price_" + currency.ToString.ToLower + """:""")  ' picks up the 3 letter currency code we entered earlier
        Dim etnpricesplit2 = Split(etnpricesplit(1), """,""")
        EXCHANGEPRICE = Decimal.Parse(etnpricesplit2(0))  ' The exchange rate
        ETNTXFEE = Integer.Parse(5)  ' Hardcoded a 5 ETN TX fee, change the value here to change ETN tx fees
        ETNCOSTBEFORETX = (Decimal.Parse(pricestring) / EXCHANGEPRICE) ' Price before TX fee added
        TOTALETNCOST = (Decimal.Parse(pricestring) / EXCHANGEPRICE) + ETNTXFEE ' Price after TX added
        HttpContext.Current.Session("ETNcost") = TOTALETNCOST.ToString  ' This is me setting a cookie to access later, can ignore if not needed

    End Sub



    '///////////////////
    ' LOOP Function to check for ETN payment!!  Default timeout = 300 seconds.
    '////////////////////
    Function Begincheck()

        Dim testrun = Timeout.Text.Split(" ")  ' checking my timeout seconds remaining and inserting this into a variable, otherwise it tends to forget!!
        Dim counter2 = Integer.Parse(testrun(2))  ' get the right part of the text (ie the numbers!)

        If (counter2 > 0) Then  ' If we have more than 0 seconds remaining

            If (counter = Nothing) Then
                counter = 300    ' If counter hasnt been set (because its a new page load) counter = 300 seconds
            End If

            Dim success As Boolean = False  ' We havent seen a payment yet.


            Dim payload As New payload() With {.payment_id = saleidstring, .vendor_address = etnwallett}  ' The all importan payload, gets saleid and etn-wallet number. Yes, I spelt wallet wrong.
            Dim signature As String = "" ' place holder for my hashed signature (payload vs secret)
            Dim serializer As New JavaScriptSerializer()
            serializedResult = JsonConvert.SerializeObject(payload)  'converts the payload to JSON format
            signature = Hashmac(serializedResult)  ' Calls a function below to HASH my signature against my key, works !

            ' Start the API request sequence, dont mess with this
            Dim myWebRequest As HttpWebRequest
            myWebRequest = CType(WebRequest.Create("https://poll.electroneum.com/vendor/check-payment"), HttpWebRequest)
            myWebRequest.Method = "POST"
            myWebRequest.ContentType = "application/json"
            Dim byteArray = System.Text.Encoding.UTF8.GetBytes(serializedResult)  ' Convert to bytes
            myWebRequest.ContentLength = byteArray.Length
            myWebRequest.Headers.Add("ETN-SIGNATURE", signature) ' If your signature is not correct it throws a gateway 502 error

            Dim dataStream As Stream = myWebRequest.GetRequestStream()  ' This writes the PAYLOAD to ETN's API server, do not touch!
            dataStream.Write(byteArray, 0, byteArray.Length)

            Try  ' This picks up successful payments, if a payment is not found the server gives a '400 bad request' error, which I believe is a bug with ETN's methods, but this gets around it.
                Dim responsex = myWebRequest.GetResponse().GetResponseStream
                Dim reader As New IO.StreamReader(responsex)
                Dim result = reader.ReadToEnd()
                reader.Close()
                Timer1.Enabled = False ' Disable the check-every-second loop!
                HttpContext.Current.Session("success") = "yes" ' This is a cookie I use to stop people from skipping straight to the receipt-confirmed webpage, ignore if no needed.

                '///////////////////////////////////////////////
                '//////////////////////////////////////////////
                ' This is where i would update my database, set cookies and other things to pass into the receipt page, memory, storage or whatver you use to save your information!
                '////////////////////////////////////////////////
                '/////////////////////////////////////////////////

                ' Call our receipt page, point this at your own link.
                ' I have placed my 'Payment Confirmed' message on the receipt page, otherwise it auto-cancels too quickly. I could fix it, but too lazy.
                Response.Redirect("Receipt.aspx")

                ' ***************THE TRICK!!************
                ' This catches the "payment not made yet" 400 bad request, errors and then re-starts the check process one second later.
                ' It also counts down from 300 (5 minutes), and rejects the payment on 0
            Catch ex As Net.WebException  ' Catch the exception error

                Dim exResponse = New StreamReader(ex.Response.GetResponseStream()).ReadToEnd  ' Read the exception error anyway!
                Dim messagesplit = exResponse.Split(" ")
                Dim messagesplit2 As String = messagesplit(1)  ' Get the status = 0 message
                status = Replace(Replace(messagesplit2, ",", " "), "", "")  ' This cuts out the annoying ,"} stuff in the message

                If (Integer.Parse(status) = 0) Then
                    counter2 = counter2 - 1 ' subtract 1 from counter
                    Timeout.Text = "Timeout in " + counter2.ToString + " seconds." ' update counter text with new number
                End If

            End Try


            ' This happens after the timer = 0
        Else
            Timer1.Enabled = False ' Disable the looping
            Response.Write("<script>alert('Alert:  Electroneum Payment has time out. \n\nRedirecting to payments screen.')</script>") ' Tell user off for not paying.
            Threading.Thread.Sleep(3) ' A 3 second delay so the user can appreciate our warning :-)
            Response.Redirect("Paymentgateway.aspx")  ' Redirects user to my payment gateway, change this to point to your own page.

        End If

        Return False 'Exits cleanly, doesnt really do anything but is necessary.
    End Function



    '///////////////
    ' HASHES THE SECRET USING 256 ALGORYTHM
    ' ////////////////////
    ' DONT CHANGE
    Public Function Hashmac(ByVal ClearString As String) As String

        Dim encoding As New System.Text.ASCIIEncoding()
        Dim getkeyByte As Byte() = encoding.GetBytes(etnsecret)
        Dim gethmacsha256 As New HMACSHA256(getkeyByte)
        Dim getmessageBytes As Byte() = encoding.GetBytes(ClearString)
        Dim hashmessage As Byte() = gethmacsha256.ComputeHash(getmessageBytes)

        Return ByteToString(hashmessage)
    End Function


    '////////////////
    'CONVERTS OUR API RESPONSE FROM JSON BACK TO A READIBLE STRING
    '////////////////
    ' DONT CHANGE
    Public Shared Function ByteToString(buff As Byte()) As String
        Dim getbinary As String = ""
        For i As Integer = 0 To buff.Length - 1
            getbinary += buff(i).ToString("X2")
        Next
        Return (getbinary)
    End Function



    '////////////////
    'CREATES THE JSON PAYLOAD ARRAY, DO NOT CHANGE DESPITE THE NAMING RULE VIOLATION!!!!!!!!
    '////////////////
    ' DONT CHANGE
    Public Class payload
        Public Property payment_id As String
        Public Property vendor_address As String
    End Class



    ' END PROGRAM
End Class