The API sends a verification code via a phone call that the user then enters into a website... basically verifying that there phone number is valid.
But I'm having trouble signing the request. No matter what I try it returns "Invalid Signature"
The API documentation:
http://docs.telesign.com/rest/content/verify-call.html
The authentication documentation:
http://docs.telesign.com/rest/content/rest-auth.html
The authentication examples:
http://docs.telesign.com/rest/content/auth-examples.html
The code:
<cffunction name="encryptHmacSHA1" returntype="binary" access="public" output="false">
<cfargument name="base64Key" type="string" required="true">
<cfargument name="signMessage" type="string" required="true">
<cfargument name="encoding" type="string" default="UTF-8">
<cfset var messageBytes = JavaCast("string",arguments.signMessage).getBytes(arguments.encoding)>
<cfset var keyBytes = binaryDecode(arguments.base64Key, "base64")>
<cfset var key = createObject("java","javax.crypto.spec.SecretKeySpec")>
<cfset var mac = createObject("java","javax.crypto.Mac")>
<cfset key = key.init(keyBytes,"HmacSHA1")>
<cfset mac = mac.getInstance(key.getAlgorithm())>
<cfset mac.init(key)>
<cfset mac.update(messageBytes)>
<cfreturn mac.doFinal()>
</cffunction>
<cfscript>
// PHONE NUMBER TO CALL
phoneNumberToCall = "15554565555";
// KEYS
keys = structNew();
keys.customerID = "D561FCF4-BA8D-4DFC-86D1-1A46DF47A308";
keys.apiKey = "mDzGHsMOc2g/ivkuINEFVh6fn/v4kdjvlTvtgFVOShu7hVWXS0eV2nLSw1FXgEzDSuOjhlKLXvneiq+YFG1/Vg==";
// DATES
dates = structNew();
dates.timeZoneInfo = GetTimeZoneInfo();
dates.dateToUse = DateAdd("h",dates.timeZoneInfo.utcHourOffset,now());
dates.signingDate = DateFormat(dates.dateToUse,"ddd, dd mmm yyyy") & " " & TimeFormat(dates.dateToUse,"HH:mm:ss") & " +0000";
// HEADERS
headers = [
"POST",
"application/x-www-form-urlencoded",
"#dates.signingDate#",
"phone_number=#phoneNumberToCall#&ucid=OTHR",
"/v1/verify/call"
];
headerText = arrayToList(headers, chr(10)) & chr(10);
// CREATE SIGNATURE
stringToSign = binaryEncode( encryptHmacSHA1(keys.apiKey, headerText), "base64");
// AUTHORIZE HEADER
Authorization = "TSA" & " " & keys.customerID & ":" & stringToSign;
</cfscript>
<cfhttp method="POST" url="https://rest.telesign.com/v1/verify/call" port="443" charset="UTF-8" result="verifyPhoneCall">
<cfhttpparam type="header" name="authorization" value="#Authorization#">
<cfhttpparam type="header" name="content-type" value="application/x-www-form-urlencoded">
<cfhttpparam type="header" name="date" value="#dates.signingDate#">
<cfhttpparam name="phone_number" value="#phoneNumberToCall#" type="formfield">
<cfhttpparam name="ucid" value="OTHR" type="formfield">
</cfhttp>
<cfdump var="#verifyPhoneCall#">
The headers need to be included in the signature with "new lines". And the docs also say that they need to be in the same order that the http tag is sending them in. I don't think I have the order correct... or even how I'm supposed to set an order in the cfhttp call.
Any help is appreciated. And yes the keys are real. I'll generate new ones soon.
Thanks,
Brian
Looking over their documentation on Constructing the CanonicalizedPOSTVariables Element it mentions that the POST body must match the string used when constructing the signature (emphasis mine):
... when you construct the signature string, you must use the body of
the POST request exactly as it is delivered to the service.
By default, cfhttpparam url encodes any formField values. Since you are not encoding those values when you construct the signature, the content submitted by cfhttp does not match. Hence the error.
Either disable automatic encoding for all of the form fields in the signature:
<cfhttpparam name="phone_number"
value="#phoneNumberToCall#"
type="formfield"
encoded="false">
... or use type="body" instead. Then you have complete control over the post content:
<cfhttpparam type="body"
value="phone_number=15554565555&ucid=OTHR">
Update:
Also, get rid of the final new line ie chr(10) in the "headerText". Otherwise your cfhttp content still will not match the signature. ie Use this:
headerText = arrayToList(headers, chr(10));
.. instead of:
headerText = arrayToList(headers, chr(10)) & chr(10);
Related
Amazon's documentation on how to verify is posted here: https://developer.amazon.com/docs/custom-skills/host-a-custom-skill-as-a-web-service.html#checking-the-signature-of-the-request
I'm stuck trying to get this to work:
Once you have determined that the signing certificate is valid, extract the public key from it.
Base64-decode the Signature header value on the request to obtain the encrypted signature.
Use the public key extracted from the signing certificate to decrypt the encrypted signature to produce the asserted hash value.
Generate a SHA-1 hash value from the full HTTPS request body to produce the derived hash value
Compare the asserted hash value and derived hash values to ensure that they match.
Here's what I have so far. I have the verification done as far as the subject and valid pem file, the issue is I have no idea how to 'Compare the asserted hash value and derived hash values to ensure that they match.'
<!---get the request sent from amazon---->
<cfset local.request = deserializeJson(
toString(getHttpRequestData().content)
)>
<!---collect headers for authentication---->
<cfif this.isTesting is False>
<cftry>
<cfset local.request.headers.SignatureCertChainUrl = getHttpRequestData().headers.SignatureCertChainUrl>
<cfcatch type="any">
<cfset local.request.request.type = "SessionEndedRequest"><!---end session if SignatureCertChainUrl not passed--->
</cfcatch>
</cftry>
<cftry>
<cfset local.request.headers.Signature = getHttpRequestData().headers.Signature>
<cflog file="Alexa" text="URL Sig: #local.request.headers.Signature#" >
<cfcatch type="any">
<cfset local.request.request.type = "SessionEndedRequest"><!---end session if Signature not passed--->
<cflog file="Alexa" text="Signature is not defined" >
</cfcatch>
</cftry>
<cfif isDefined("local.request.headers.SignatureCertChainUrl") and
isDefined("local.request.headers.Signature")>
<cfif find('https://s3.amazonaws.com/echo.api/',local.request.headers.SignatureCertChainUrl)
or find('https://s3.amazonaws.com:443/echo.api/',local.request.headers.SignatureCertChainUrl)><!---not ssl so kill it--->
<cflog file="Alexa" text="URL Chain: #local.request.headers.SignatureCertChainUrl#" >
<cfset local.request.headers.SignatureCertChainUrlFormatted = replacenocase(local.request.headers.SignatureCertChainUrl,'echo.api/../echo.api','echo.api')>
<cfhttp url="#local.request.headers.SignatureCertChainUrlFormatted#" method="get"></cfhttp>
<cffile action="write"
file="C:\inetpub\alexa\cert\echo.pem"
output="#cfhttp.FileContent#">
<!---check date is valid---->
<cfexecute name="C:\OpenSSL-Win32\bin\openssl.exe"
arguments="x509 -noout -dates -in C:\inetpub\alexa\cert\echo.pem"
variable="local.cert.OpenSSL_dates"
timeout="10" >
</cfexecute>
<cfset local.cert.datesFormatted = replacenoCase(local.cert.OpenSSL_dates,'notbefore','')>
<cfset local.cert.datesFormatted = replacenoCase(local.cert.datesFormatted,'notafter','')>
<cfset local.cert.datesFormatted = replacenoCase(local.cert.datesFormatted,'=','')>
<cfset local.cert.notBefore = trim(listgetat(local.cert.datesFormatted,1,'='))>
<cfset local.cert.notAfter = trim(listgetat(local.cert.datesFormatted,2,'='))>
<cfif datecompare(convertCertTime(local.cert.notBefore),now()) is '-1' and
datecompare(convertCertTime(local.cert.notAfter),now()) is '1'>
<!---cert date is valid--->
<cfelse>
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
<!---check 'echo-api.amazon.com' in subject---->
<cfexecute name="C:\OpenSSL-Win32\bin\openssl.exe"
arguments="x509 -noout -subject -in C:\inetpub\alexa\cert\echo.pem"
variable="local.cert.OpenSSL_Subject"
timeout="10" >
</cfexecute>
<cfif NOT findNOcase('echo-api.amazon.com',local.cert.OpenSSL_Subject)>
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
<!---check 'CN=Symantec Class 3 Secure Server CA' in issuer---->
<cfexecute name="C:\OpenSSL-Win32\bin\openssl.exe"
arguments="x509 -noout -issuer -in C:\inetpub\alexa\cert\echo.pem"
variable="local.cert.OpenSSL_issuer"
timeout="10" >
</cfexecute>
<cfif NOT findNOcase('Symantec Class 3 Secure Server CA',local.cert.OpenSSL_issuer)>
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
<cfexecute name="C:\OpenSSL-Win32\bin\openssl.exe"
arguments="x509 -noout -pubkey -in C:\inetpub\alexa\cert\echo.pem"
variable="local.cert.OpenSSL_Pubkey"
timeout="120" >
</cfexecute>
<cffile action="write"
file="C:\inetpub\alexa\keys\#local.request.request.requestId#.key"
output="#local.cert.OpenSSL_Pubkey#">
<!---decyrpt header signature---->
<!----Base64-decode the Signature header---->
<cfset local.cert.encryptedSig = toString(ToBinary(local.request.headers.Signature)) />
<cffile action="write"
file="C:\inetpub\alexa\keys\#local.request.request.requestId#.sig"
output="#local.cert.encryptedSig#">
<cfelse>
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
<!----end of header decrypting----->
<cfelse>
<!---if either of these are not defined kill the session---->
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
</cfif>
Try charsetDecode to utf-8 before Base64 decode
Use this before Base64 decode
<CFSET local.request.headers.Signature = charsetDecode( local.request.headers.Signature, "utf-8" )>
I'm trying to get transaction details from PayPal's SOAP API but I'm running into into error from PayPal. It returns the error:
The transaction id is not valid
I know it's a valid transaction ID since I'm I'm able to get transaction details using the PayPal NVP API but maybe I have the SOAP request formatted incorrectly. I followed the PayPal SOAP API examples I can find across the web to construct the SOAP XML but they are slim. I'm using mac's PAW program to send a SOAP request to PayPal's API but this problem should be reproducible using an HTTP client.
I tried to use PayPal's REST API but there's no method to get transaction details (e.g. name, email, amount paid, custom fields) . I also tried to use the NVP (Name-Value-Pair) API and I do get back the transaction details but it doesn't give me all of the stored custom fields for a transaction. When I log in to PayPal, and view a single transaction, I can see all of the custom fields for that transaction, so I know they're being stored.
The SOAP API is my last hope.
Here's the SOAP envelope request I'm using:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="urn:ebay:api:PayPalAPI" xmlns:ebl="urn:ebay:apis:eBLBaseComponents" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:ed="urn:ebay:apis:EnhancedDataTypes">
<soapenv:Header>
<ns:RequesterCredentials>
<ebl:Credentials>
<ebl:Username>soap_api_username_here</ebl:Username>
<ebl:Password>soap_api_password_here</ebl:Password>
<ebl:Signature>soap_api_signature_here</ebl:Signature>
</ebl:Credentials>
</ns:RequesterCredentials>
</soapenv:Header>
<soapenv:Body>
<ns:GetTransactionDetailsReq>
<ns:GetTransactionDetailsRequest>
<ebl:Version>93.0</ebl:Version>
<ebl:TransactionID>8FX18476NR449891W</ebl:TransactionID>
</ns:GetTransactionDetailsRequest>
</ns:GetTransactionDetailsReq>
</soapenv:Body>
</soapenv:Envelope>
Here's the response I receive from the PayPal SOAP API:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext" xmlns:ed="urn:ebay:apis:EnhancedDataTypes" xmlns:ebl="urn:ebay:apis:eBLBaseComponents" xmlns:ns="urn:ebay:api:PayPalAPI">
<SOAP-ENV:Header>
<Security xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext" xsi:type="wsse:SecurityType"/>
<RequesterCredentials xmlns="urn:ebay:api:PayPalAPI" xsi:type="ebl:CustomSecurityHeaderType">
<Credentials xmlns="urn:ebay:apis:eBLBaseComponents" xsi:type="ebl:UserIdPasswordType">
<Username xsi:type="xs:string"/>
<Password xsi:type="xs:string"/>
<Signature xsi:type="xs:string"/>
<Subject xsi:type="xs:string"/>
</Credentials>
</RequesterCredentials>
</SOAP-ENV:Header>
<SOAP-ENV:Body id="_0">
<GetTransactionDetailsResponse xmlns="urn:ebay:api:PayPalAPI">
<Timestamp xmlns="urn:ebay:apis:eBLBaseComponents">2016-08-02T16:43:02Z</Timestamp>
<Ack xmlns="urn:ebay:apis:eBLBaseComponents">Failure</Ack>
<CorrelationID xmlns="urn:ebay:apis:eBLBaseComponents">a464c181339f4</CorrelationID>
<Errors xmlns="urn:ebay:apis:eBLBaseComponents" xsi:type="ebl:ErrorType">
<ShortMessage xsi:type="xs:string">Transaction refused because of an invalid argument. See additional error messages for details.</ShortMessage>
<LongMessage xsi:type="xs:string">The transaction id is not valid</LongMessage>
<ErrorCode xsi:type="xs:token">10004</ErrorCode>
<SeverityCode xmlns="urn:ebay:apis:eBLBaseComponents">Error</SeverityCode>
</Errors>
<Version xmlns="urn:ebay:apis:eBLBaseComponents">93.0</Version>
<Build xmlns="urn:ebay:apis:eBLBaseComponents">000000</Build>
<PaymentTransactionDetails xmlns="urn:ebay:apis:eBLBaseComponents" xsi:type="ebl:PaymentTransactionType">
<ReceiverInfo xsi:type="ebl:ReceiverInfoType"/>
<PayerInfo xsi:type="ebl:PayerInfoType">
<PayerStatus xsi:type="ebl:PayPalUserStatusCodeType">verified</PayerStatus>
<PayerName xsi:type="ebl:PersonNameType"/>
<Address xsi:type="ebl:AddressType">
<AddressOwner xsi:type="ebl:AddressOwnerCodeType">PayPal</AddressOwner>
<AddressStatus xsi:type="ebl:AddressStatusCodeType">None</AddressStatus>
</Address>
</PayerInfo>
<PaymentInfo xsi:type="ebl:PaymentInfoType">
<TransactionType xsi:type="ebl:PaymentTransactionCodeType">none</TransactionType>
<PaymentType xsi:type="ebl:PaymentCodeType">none</PaymentType>
<PaymentStatus xsi:type="ebl:PaymentStatusCodeType">None</PaymentStatus>
<PendingReason xsi:type="ebl:PendingStatusCodeType">none</PendingReason>
<ReasonCode xsi:type="ebl:ReversalReasonCodeType">none</ReasonCode>
</PaymentInfo>
<PaymentItemInfo xsi:type="ebl:PaymentItemInfoType">
<Subscription xsi:type="ebl:SubscriptionInfoType"/>
<Auction xsi:type="ebl:AuctionInfoType"/>
</PaymentItemInfo>
</PaymentTransactionDetails>
</GetTransactionDetailsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I'm not sure what I'm doing wrong but maybe someone with more experience can spot the error easier than I can. I responded to another user's question about the PayPal REST API and getting transaction details from that but as far as I know, there's no way to do that Get customer details after transaction . If you have found a way to accomplish this with the REST API, let me know cause I would much rather use REST than SOAP.
Thanks.
The error message is a red herring. PayPal can't find any TransactionId, reporting the empty TransactionId as invalid.
The TransactionId element belongs to the urn:ebay:api:PayPalAPI namespace. Your XML attaches it to the urn:ebay:apis:eBLBaseComponents namespace. All you need to do is change the ebl:TransactionId to ns:TransactionId.
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="urn:ebay:api:PayPalAPI" xmlns:ebl="urn:ebay:apis:eBLBaseComponents" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:ed="urn:ebay:apis:EnhancedDataTypes">
<soapenv:Header>
<ns:RequesterCredentials>
<ebl:Credentials>
<ebl:Username>soap_api_username_here</ebl:Username>
<ebl:Password>soap_api_password_here</ebl:Password>
<ebl:Signature>soap_api_signature_here</ebl:Signature>
</ebl:Credentials>
</ns:RequesterCredentials>
</soapenv:Header>
<soapenv:Body>
<ns:GetTransactionDetailsReq>
<ns:GetTransactionDetailsRequest>
<ebl:Version>204.0</ebl:Version>
<ns:TransactionID>8FX18476NR449891W</ns:TransactionID>
</ns:GetTransactionDetailsRequest>
</ns:GetTransactionDetailsReq>
</soapenv:Body>
Check this example at the PayPal KB.
I would have put this as a comment but it is pretty full of goobly gook. At the expense of being way off I might be of some help maybe.
So my vb.net code sends a form to paypal which includes "notify_url".
' determining the URL to work with depending on whether sandbox or a real PayPal account should be used
If strRealOrSand = "Sand" Then
URL = "https://www.sandbox.paypal.com/cgi-bin/webscr"
business = "x#xxx.com" ' AppSettings("BusinessEmail") (sandbox account business email)
ElseIf strRealOrSand = "Real" Then
URL = "https://www.paypal.com/cgi-bin/webscr"
business = "xxx#xxx.com" ' AppSettings("BusinessEmail") (real pay pal account account business email)
End If
notify_url = "http://www.xxxxx.com/accounts/done.aspx"
<form id="payForm" method="post" action="<%Response.Write (URL)%>" >
<input type="hidden" name="cmd" value="<%Response.Write (cmd)%>" />
<input type="hidden" name="business" value="<%Response.Write (business)%>" />
<input type="hidden" name="item_name" value="<%Response.Write (item_name)%>" />
<input type="hidden" name="amount" value="<%Response.Write (amount)%>" />
<input type="hidden" name="no_shipping" value="<%Response.Write (no_shipping)%>" />
<input type="hidden" name="return" value="<%Response.Write (return_url)%>" />
<input type="hidden" name="rm" value="<%Response.Write (rm)%>" />
<input type="hidden" name="notify_url" value="<%Response.Write (notify_url)%>" />
<input type="hidden" name="cancel_return" value="<%Response.Write (cancel_url)%>" />
<input type="hidden" name="currency_code" value="<%Response.Write (currency_code)%>" />
<input type="hidden" name="custom" value="<%Response.Write (row_id)%>" />
</form>
<script type="text/javascript">
document.forms["payForm"].submit ();
</script>
</body>
Then in my "notify_url" page load it gets what PayPal sends back after transaction completes. You'll notice there is a ton of debug emails being sent back to me. This was my doing.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim vReceived As String = ""
Dim vFormValues As String = ""
Dim vResponder As String = ""
Dim strE As String = ""
Dim intAccountID As Integer = 0
Dim intCreditsPurchased As Integer = 0
Dim vWebRequest As System.Net.HttpWebRequest
Dim vSSend As Boolean = False
'vWebRequest = CType(System.Net.WebRequest.Create("https://www.sandbox.paypal.com/cgi-bin/webscr"), System.Net.HttpWebRequest)
vWebRequest = CType(System.Net.WebRequest.Create("https://www.paypal.com/cgi-bin/webscr"), System.Net.HttpWebRequest)
vWebRequest.Method = "POST"
vWebRequest.ServicePoint.Expect100Continue = False
vWebRequest.ContentType = "application/x-www-form-urlencoded"
Try
vFormValues = Encoding.ASCII.GetString(Request.BinaryRead(Request.ContentLength))
vReceived = "cmd=_notify-validate&" & vFormValues
Catch ex As Exception
sSend_Mail_From_done_aspx("Requested Form.ToString", ex.ToString)
End Try
vWebRequest.ContentLength = vReceived.Length
Dim vStreamOut As System.IO.StreamWriter = New System.IO.StreamWriter(vWebRequest.GetRequestStream(), Encoding.ASCII)
vStreamOut.Write(vReceived)
vStreamOut.Close()
Dim vStreamIn As New System.IO.StreamReader(vWebRequest.GetResponse().GetResponseStream())
vResponder = vStreamIn.ReadToEnd()
vStreamIn.Close()
Dim vFieldName As String
Dim vFieldValue As String = ""
Dim vFields As New Collection
For Each vFieldName In Request.Form
'strE = strE & Request.Form.Item(vFieldName) & " "
strE &= vFieldName & ": " & Request.Form.Item(vFieldName) & vbCrLf
'vFieldValue = Request.Form.Item(vFieldName)
'vFields.Add(Decode(vFieldValue), Decode(vFieldName).ToLower)
Next
sSend_Mail_From_done_aspx("BEFORE VERIFIED CHECK, WHAT vResponder CONTAINS", strE)
Dim transactionID As String = ""
Dim dblAmount As Double
Dim intRowID As Integer
Dim dblPayPalFee As Double
Dim strMemo As String = ""
Dim strPayerEmail As String = ""
Dim strPaymentDate As String = ""
If Trim(vResponder).ToUpper = "VERIFIED" Then
For Each vFieldName In Request.Form
strE &= vFieldName & ": " & Request.Form.Item(vFieldName) & vbCrLf
Next
sSend_Mail_From_done_aspx("VERIFIED CAME THROUGH", strE)
Try
transactionID = Request.Form.Item("txn_id").ToString()
dblAmount = CType(Request.Form.Item("payment_gross"), Double)
intRowID = CType(Request.Form.Item("custom"), Integer)
dblPayPalFee = CType(Request.Form.Item("payment_fee"), Double)
If Len(Request.Form.Item("memo") & "") <> 0 Then
strMemo = Request.Form.Item("memo").ToString.Replace("'", "")
End If
strPayerEmail = Request.Form.Item("payer_email").ToString
strPaymentDate = Request.Form.Item("payment_date").ToString
Catch ex As Exception
sSend_Mail_From_done_aspx("Request.QueryString)", ex.ToString)
End Try
Try
'==============================
'SAVE TRANSACTION INFO HERE
'==============================
Dim sb As New StringBuilder
sb.Append("UPDATE dbo.tblTransactions ")
sb.Append("SET pp_txn_id='" & transactionID & "'")
sb.Append(", pp_payment_gross=" & dblAmount)
sb.Append(", pp_mc_fee=" & dblPayPalFee)
sb.Append(", memo='" & strMemo & "'")
sb.Append(", pp_payer_email='" & strPayerEmail & "'")
sb.Append(", pp_payment_date='" & strPaymentDate & "'")
sb.Append(" WHERE RowID =" & intRowID)
'SEND SQL TO DEVELOPER
sSend_Mail_From_done_aspx("INSERT statement BEFORE action", sb.ToString)
Dim conn As New SqlConnection(f1.fUseThisConnection(Server.MachineName))
Dim cmd As New SqlCommand(sb.ToString, conn)
cmd.Connection.Open()
cmd.ExecuteNonQuery()
'=========================================================
'UPDATE ACCOUNT INFO HERE (ADD CREDITS TO CURRENT AMOUNT)
'=========================================================
Dim dr As System.Data.SqlClient.SqlDataReader
sb.Length = 0
'GET ACCOUNT ID, AND CreditsPurchased
sb.Append("SELECT AccountID, CreditsPurchased FROM dbo.tblTransactions ")
sb.Append(" WHERE RowID =" & intRowID)
cmd.CommandText = sb.ToString
dr = cmd.ExecuteReader()
If dr.Read() Then
intAccountID = dr("AccountID")
intCreditsPurchased = dr("CreditsPurchased")
End If
dr.Close()
sb.Length = 0
'AT 1.10 A CREDIT, WE DIVIDE THE AMOUNT PAYPAY CHARGES BY THIS TO GET CREDITS PURCHASED
sb.Append("UPDATE dbo.tblAL SET Credits = Credits + " & intCreditsPurchased)
sb.Append(" WHERE AccountID =" & intAccountID)
cmd.CommandText = sb.ToString
cmd.ExecuteNonQuery()
'SEND ACCOUNT UPDATE AMOUNT TO DEVELOPER
sSend_Mail_From_done_aspx(intCreditsPurchased & " CREDITS ADDED TO ", sb.ToString)
cmd.Dispose()
conn.Close()
conn = Nothing
MySession.Credits = intCreditsPurchased
Catch ex As Exception
sSend_Mail_From_done_aspx("tblTransactions NOT UPDATED with Transaction Info", ex.ToString())
End Try
Else
sSend_Mail_From_done_aspx(Trim(vResponder).ToUpper, "TRANSACTION NOT VERIFIED")
End If
End Sub
I think the request/responses are these below:
submitted form
URL = "https://www.paypal.com/cgi-bin/webscr"
sends back to this inside the "notify_url" that is submitted
Dim vWebRequest As System.Net.HttpWebRequest
Dim vSSend As Boolean = False
'vWebRequest = CType(System.Net.WebRequest.Create("https://www.sandbox.paypal.com/cgi-bin/webscr"), System.Net.HttpWebRequest)
vWebRequest = CType(System.Net.WebRequest.Create("https://www.paypal.com/cgi-bin/webscr"), System.Net.HttpWebRequest)
Sure would be nice to have a "PayPalFiddle" haha
Using Coldfusion I would like to create a REST service
I would like to post it to: https://www.test.co.za/ using the username "person1" and password "password1".
The data type would be: application/json
And I would like to pass the following parameters:
callbackURL (string)
amount (bigdecimal)
reference (string)
description (string)
This will then return:
reference (string)
redirectURL (string)
status (string)
This is what I have got so far:
index.cfm
<cfset restInitApplication("C:\ColdFusion10\cfusion\wwwroot\restApp","IIT")>
<cfhttp url="http://127.0.0.1:8500/rest/IIT/rest" method="get">
<cfoutput>#cfhttp.filecontent#</cfoutput>
rest.cfc
<cfcomponent rest="true" restpath="restService">
<cffunction name="sayHello" access="remote" returntype="String" httpmethod="GET">
<cfset callbackURL = "https://www.google.com">
<cfset amount = "100,50">
<cfset reference = "123456789">
<cfset description = "This is a description">
<cfreturn rest>
</cffunction>
</cfcomponent>
I would like to know if I am on the right track and how I would post my values to https://www.test.co.za/ with a username and password
I am not sure if it will look something like this:
<cfhttp
url="https://www.test.co.za/"
method="post"
port="8500"
result="res">
</cfhttp>
Thanks in advance
I'm trying to do server side facebook connect, but the sdk (get it here) provided gives the following error:
Invalid CFML construct found on line 523 at column 78.
ColdFusion was looking at the following text:
{
And it doesn't explain why it's throwing this error. I'm not good at cfscript, so I don't know whether the sdk uses the correct syntax, but it throws the error on this function, at the braces of the struct in the function arguments:
private String function getUrl(String path = "", Struct parameters = {})
{
var key = "";
var resultUrl = "https://www.facebook.com/" & arguments.path;
if (structCount(arguments.parameters)) {
resultUrl = resultUrl & "?" & serializeQueryString(arguments.parameters);
}
return resultUrl;
}
I had thought that using an sdk would be a no brainer, but apparently I'm missing something.
What am I doing wrong?
Part 2:
The code now comes to a halt at:
for (var propertyName in arguments.properties) {
httpService.addParam(type="formField", name=propertyName, value=arguments.properties[propertyName]);
}
Are you not allowed to use a for loop in cfscript?
Try structNew() or "#structNew()#" instead of {}
This should work for connecting to Facebook and getting an access token:
<cfset appID = ""/>
<cfset secret_key = ""/>
<cfset app_url = ""/>
<cfparam name="URL.Code" default="0">
<cfparam name="URL.state" default="0">
<cfparam name="SESSION.Redirect" default="0">
<cfset code_ = URL.Code>
<cfif code_ EQ "" OR code_ EQ 0>
<cfset SESSION.State = Hash(CreateUUID(),"MD5")>
<cfset dialog_url = "http://www.facebook.com/dialog/oauth?client_id=" & appID & "&redirect_uri=" & app_url & "&scope=email,user_photos,publish_stream" & "&state=" & SESSION.State>
<cflocation url="#dialog_url#" addtoken="no">
</cfif>
<cfif SESSION.State EQ URL.State>
<cfset token_url = "https://graph.facebook.com/oauth/access_token?client_id=" & appID & "&redirect_uri=" & app_url & "&client_secret=" & secret_key & "&code=" & code_>
<cfhttp url="#token_url#" result="AccessToken" method="GET">
<cfelse>
<p>The state does not match. You may be a victim of CSRF.</p>
</cfif>
In my app I have to send email to recipient who has umlauts in domain name.
Example:
"test#äöü.test.com"
I'm using cfmail tag and I'm getting such error:
"invalid definition for attribute to at tag mail"
"Invalid E-Mail Address definition (test#äöü.test.com)"
Is there any way to send email to such recipients in coldfusion?
There is even a easier solution! Why not use Oracles built in class:
http://download.oracle.com/javase/6/docs/api/java/net/IDN.html#toUnicode(java.lang.String)
Then you only have to do this (example shows from punycode to Unicode):
<cfset strUrl = "xn--land-poa.se" />
<!--- Create a Java URL. --->
<cfset jUrl = CreateObject( "java", "java.net.IDN" ).toUnicode(strUrl) />
<cfoutput>
#jUrl#
You don´t have to download anything!
I'm no I18N expert but I was intrigued enough to investigate and come up with the following solution.
The problem is essentially how to send mail to Internationalised Domain Names (IDN), i.e. those which contain non-ASCII characters. IDNs are valid nowadays but not recognized by many systems including Java (and therefore ColdFusion, which uses the Java validation for CFMAIL address fields - hence the error you're seeing).
For a system to recognise an IDN it needs to be converted to an ASCII form called Punycode. For example müller.org needs to be converted to xn--mller-kva.org
LibIdn is an OS java library that will do this and the following code shows how you can hook it up to CF using Mark Mandel's JavaLoader.
<cffunction name="convertIdnToAscii" returntype="string" output="false">
<cfargument name="domain" type="string" required="true">
<cfscript>
var local = {};
// these paths assume the JavaLoader folder and the libidn-1.22.jar are in the same folder as the cfm template.
local.javaLoaderPath = "javaLoader.JavaLoader";
local.idnLibPath = ExpandPath( "libidn-1.22.jar" );
// convert the IDN lib path to an array which is what JavaLoader expects
local.libPathArray = [ local.idnLibPath ];
//load the IDN Lib
loader = CreateObject( "component",local.javaLoaderPath ).init( local.libPathArray );
// create an instance of the IDN lib
local.idn = loader.create( "gnu.inet.encoding.IDNA" ).init();
// convert the domain name
return local.idn.toASCII( arguments.domain );
</cfscript>
</cffunction>
<cffunction name="convertIdnAddress" returntype="string" output="false">
<cfargument name="address" type="string" required="true">
<cfscript>
var local = {};
local.domain = GetToken( arguments.address,2,"#" );
local.converted = convertIdnToAscii( local.domain );
return Replace( arguments.address,local.domain,local.converted );
</cfscript>
</cffunction>
<!--- Loop over a list of addresses and convert them if necessary --->
<cfset processedAddresses = []>
<cfloop list="test#äöü.test.com,test#example.com" index="address">
<cfif( NOT IsValid( "email",address ) )>
<cfset address = convertIdnAddress( address )>
</cfif>
<cfmail server="0.0.0.0" from="sender#mydomain.com" to="#address#" subject="test">Message</cfmail>
<cfset ArrayAppend( processedAddresses,address )>
</cfloop>
<cfdump var="#processedAddresses#">
This will send 2 emails (to a non-existent mailserver) and dump the converted addresses:
test#xn--4ca0bs.test.com
test#example.com
Notes:
To get the libidn jar file, download and extract the tar and look for it in the Java directory
The above assumes the libidn jar and JavaLoader package are located in the same folder as the template contain the CF code
The above should work on CF8 and above, although I've only tested it on CF9.
Be aware there's no error handling for addresses that might be invalid for reasons other than it containing an IDN.