Zuora - How to get invoice PDF and display to user - invoice

Short question: Using the get_invoices endpoint, when I try to access the URL from the InvoiceFiles.pdfFileUrl response, it pops up a api.zuora login form. I need my customers to be able to access these PDFs.
If I enter my Zuora creds, it will display the invoice, but of course my customers don't have Zuora creds.
Is there some sort of setting to allow customers to view PDFs from the URL?
Long Question:
The get_invoices endpoint returns 2 items of interest.
body is the REST URL of the invoice PDF file.
and
InvoiceFiles returns
id ID of the invoice PDF file. This is the ID for the file object and different from the file handle id in the pdfFileUrl field. To open a file, you need to use the file handle ID.
versionNumber Version number of the invoice PDF file
pdfFileUrl REST URL for the invoice PDF file. Click the URL to open the invoice PDF file.
Is there a difference between what is returned by body and InvoiceFiles.pdfFileUrl, and how do I use them correctly?
The pdfFileUrl can return multiple files. Each time the invoice is update (the customer pays etc) it generates another file. The most recent is the at index 0.
However trying to access any of the URLs, I get a api.zuora login form. If I enter my Zuora creds, it will display the invoice, but of course my customers don't have Zuora creds.
The example on the endpoint page has both the body and the pdfFiles return as blank so that doesn't help much.
Searched through their community for a while, nothing couldn't find anything remotely similar to my issue.

We finally figured out how to do this. Has to be done server side.
First step was to call "/transactions/invoices/accounts/{accountId}" to get a list of invoices.
Second, pick the invoice out of the list that matched the invoice number we were trying to view.
On that object is a list called "invoiceFiles" - if it was non-empty, grab the first item.
Use the "pdfFileUrl" property on that item as the URL to fetch the PDF from, but in the GET request, include headers "apiAccessKeyId" and "apiSecretAccessKey" with the values set to our applicable api key. This eliminates the auth problem, but also makes it so you have to do this on your backend to avoid exposing your apiAccessKeyId and Secret.
Assuming the request for the PDF coming into us was authenticated, we'd do a pipe command on the response coming back from Zuora onto the outgoing response we are currently handling on our server: zuoraResponse.pipe(ourOutgoingResponseObj)
This will display the PDF directly to the user.

The best practice would be to use an authorization cookie. The cookie authorizes the user to make calls to the REST API for the duration specified in Administration > Security Policies > Session timeout in Zuora settings. The cookie expiration time is reset with this duration after every call to the REST API.
To obtain a cookie, call the REST connections resource:
curl -X POST \
-H "apiAccessKeyId: dummyUser" \
-H "apiSecretAccessKey: dummyPassword" \
-H "Content-Type: application/json" \
-d '{}' \
"https://rest.zuora.com/v1/connections"
Once the connection is established, subsequent API calls will work without the apiSecretAccessKey and apiAccessKeyId in the header.
Please find more details from their new API document.
https://www.zuora.com/developer/api-reference/

Related

Set Excel / Word Online document readonly using Graph API

When an Excel or Word file on SharePoint is opened,it is in edit mode by default.From Excel/Word online menu, there is a menu option to set the file read-only, called "Protect Workbook" in Excel inline and "Protect Document" in Word online, as shown in the screenshot.
Next time the file is open in Excel/Word online, it is opened in read-only mode and shows an "Edit Anyway" button to switch to edit mode, which is exactly what I need.
Question is: How can I use Graph API to programatically set an Excel or Word document as read-only?
HTTP request
POST /workbook/worksheets/{id|name}/protection/protect
Request headers
Name Description
Authorization Bearer {token}. Required.
Workbook-Session-Id Workbook session Id that determines if changes are persisted or not. Optional.
Request body
In the request body, provide a JSON object with the following parameters.
Parameter Type Description
options WorkbookWorksheetProtectionOptions Optional. sheet protection options.
Response
If successful, this method returns 200 OK response code. It does not return anything in the response body.
Kindly look at https://learn.microsoft.com/en-us/graph/api/worksheetprotection-protect?view=graph-rest-1.0&tabs=http for more Information

Bitcoin URI "r=" param. How it works?

Example:
bitcoin:?r=https://bitpay.com/i/WEZPwt4tjjN9UXZrxSnTKu
It not gone work now, because bitpay payment is available only 15 minutes. But if you have an active payment it opens your Bitcoin app (f.e. Bitcoin core) and make your forms filled.
How to do smartlink like this? If im using simply URI I can put bitcoin:1ADDRESS?amount=1 etc., but I want to do it like a Bitpay.
The argument r= is defined in BIP-72 and means that more details must be obtained through the link
Bitpay uses Bitcoin Payment Protocol defined in BIP 70 Protocol
But if you open the link in a browser, it will show bitpay invoice page. In this case you need to pass a HTTP header to get the real payment request:
wget --header="Accept: application/bitcoin-paymentrequest" https://bitpay.com/i/WEZPwt4tjjN9UXZrxSnTKu
It will return a protocol buffer, is what your application should do.

How can I secure this form post from manipulation

I have a very unique situation. I am building an application where a user uploads a QR code to my site, and when decoded, it has a matching ID already stored in the DB (as in I already have a record of the qr code before the user uploads it)
When they upload it, I decode it, which is a base64 string like so 6BbW0pxO0YENxn38HMUbcQ==
Like I said, That code corresponds to some information, and after they upload the QR image, I redirect them to one more page, which shows them the qr code, the corresponding information stored in the DB, and they are also prompted with a submit button. When pressed, I take note that they have confirmed, and I do some other things.
To elaborate
As a user I go to www.url.com/code/upload and upload an image. I am then redirected to /code/new with the page displaying the data stored in the DB from the correspond decoding of the image.
How can I make the submit button on /code/new reliable? Here are the solutions I can think of, and their vulnerabilities
Propagate /code/new with the correspond data stored in the DB, lets say #username and #movie into a form, with a submit button and POST the data to the server
This is dangerous because I don't think anything stops someone from editing the DOM and changing #username and #movie to something else
Pass the unique base64 identifier in the parameters such like, /code/new?id=STRING
Then when you submit, the string gets passed to the handling controller action, but i feel that this is not safe because then users can attempt to guess the strings and make concurrent post requests.
Essentially, I have a user upload a qr code, and after submission, I need to verify to verify that they were the one that uploaded the image. I lose all state, and information after they upload the image.
A proposed solution:
After the user uploads the image, create a unique string and store it in the session and also a record in the database (A user is logged in, so its the current_user.session_token), then when the user clicks submit on /uploads/new, I grab the session token, and verify that the current_user.session_token == session_token.
At this point, I can only verify that the current user was the one that uploaded the image.. I then need to somehow grab the base64 string that was from the uploaded QR code.
Another proposed solution: I temporarily put the base64 string as an attribute of the user when they upload the file. So I will have current_user.session_token and current_user.base64_string. Then when the user clicks on the 2nd submit button, I do something like
#check if the user's token is equal to the sessions, and the string is not nil
if current_user.session_token == session_token && !current_user.base64_string.nil?
data = current_user.base64_string
#hooray! I have the QR code
end
Then delete the session token, and then delete the current_user's base64_string and session_token
if a malicious user attempts to forge their session token, it won't match their's store in the database, then when I handle the post request, I will not proceed. But If a legitimate user makes the second post request, the session Id matches, and I am able to grab the base64 string.
TL;DR, I need 2 concurrent post requests that carry the information without losing it, and can verify that both the first and second post requests were done by the same user.
If anyone had the patience to read through that, I appreciate it! if there are any suggestions I would greatly appreciate it, or if you think my solution is sufficient or not, please let me know. Thanks!
Sign the parameters generated from the first request, and verify the signature when you process the second request.
The technology to use for this is HMAC. Here's how to use one version available in Ruby:
require 'openssl'
secret = 'ABCDEFGHIJKLMNOP'
data = 'user:code'
signature = OpenSSL::HMAC.hexdigest( 'sha256', secret, data )
p signature
Output:
"bd7194c0604902d6594694d25e7f27bdc2d10926638e0ce8bdda3f6debb37f6a"
This is how you can use it to link two HTTP routes together so that the second one can trust that parameters sent to it via the first one have not been tampered with:
When the first route is called, generate or fetch a secret. It is important that this secret value is not ever sent or exposed to the end user. It can simply be application configuration (which then applies to all linked requests), but if you can store it associated with perhaps the QR code, then the strongest protection is to generate a long random string just before creating the signature, and to store it ready to use to confirm the second step. Something like SecureRandom.hex is great for a short-term secret if you have somewhere server-side to store it.
Combine all the parameters on the form that you want to be tamper-free into one long message. Easiest thing to do is .join them in an array, and you should use a delimiter that is not allowed in any value, and that you are also not accepting due to validation. This string is the value to use for data in the example.
Generate the form that calls the second route. In addition to the params you want to accept at next stage, add the signature value generated as above. Do not send the value of secret to the client by putting in the form or cookie etc.
When you receive the request from the second route to finalise the multi-stage request, generate the signature from the user-sent params (after validating them), and compare with the one sent to you from the form. If it is the same, then the request is valid. If it is different then the data may have been tampered (provided you have no bugs - do check things such as consistent character encoding if any param can contain non-ASCII characters)
Provided you have kept the secret truly secret from the end user, they have next to no chance of generating a correct signature. Only your code in routes one and two knows how to do it (because it has access to correct secret, not because of any special fact on how it is written). Therefore you can trust that the values have not been modified.

How do I reverse a t.co URL to the originating Tweet?

I'm going through our site analytics, and have a load of t.co URLs which were referrers to a promotion we were doing. I'm trying to figure out if there is a way to reverse those back to the original tweet where they originated, through the Twitter API or other means. I can't seem to find a good means to do this though, is there one?
This is not possible with the public APIs that twitter provides.
If I understand correctly you want to find a tweet that originally had a particular t.co link embedded. i.e. The t.co when followed resolves to your site, not the twitter tweet.
When a t.co forward points to a tweet, it goes to the web page for that tweet and the HTML for the page will include the canonical URL.
The ugly way to get this information is to use wget or curl to grab the HTML destination which will include the URL for your initial tweet.
A better way to do it is with the Python module, Requests (you will need to install this module first). Here's a quick command line script that will do it:
#!/usr/bin/env python
import requests
shorturl = raw_input("Enter the shortened URL in its entirety: ")
r = requests.get(shorturl)
print("""
The shortened URL forwards to:
%s
""" % r.url)
That code will work on any of those URL shortening services, not just Twitter's t.co site.
I did my testing with Python 2.7, but chances are that the above code will work with Python 3.x. Either way, Requests is your friend, see the documentation for details:
http://docs.python-requests.org/en/latest/index.html
The redirection and history section covers this example.
I don't know of a way to do it through the Twitter API and it may not be possible if all URL shortening is automatic. Still an API based solution would only work with the t.co addresses, whereas the code above will work on any other shortened URL or any URL which redirects (e.g. HTTP 301 or 302 response codes) to another location.
Edit (better a bit later than never): After using the above to find where the t.co forward actually points to, there will be three or four types of possible results. The most common being that it is what the OP believes they all are, a shortening to a URL pasted into a tweet and, to be fair, that is what most of them are.
The other possibilities are that it links back to the tweet itself, this usually only appears with some rather long tweets (not sure how much that increases in frequency with the character limit increase too); as well as forwarding to the URL of a status independent of a the tweet author's status URL, which is often the case with embedded media (images and video); plus forwards to the URL of a tweet which is being quote tweeted or retweeted.
Given the OP's original scenario, none of those internal Twitter usages should ever be seen and only the "normal" forwarding is of concern here. Now searching for the t.co address at twitter.com avails us nothing, regardless what combinations are used.
Searching the target address, however, that which is revealed by scripts like the one at the start of this answer, however, is quite another matter. That will produce the the results of every tweet which is publicly accessible and which posted that link. There are, however, some drawbacks including:
The search results will include tweets where other forwarding services were used as well.
There is no way to tell whether all the tweets which linked to that URL generated the same t.co address or not.
If not, there is no way to see which t.co forward was utilised by which tweet.
Nevertheless, in conjunction with complete referrer logs on a web server, it may be possible to narrow that further. Assuming the referrer URL reports the URL of the tweet and not simply twitter.com. That, however, is more likely to be determined by the manner in which the person clicking on the link did so (i.e. were they just seeing the tweet in a stream or had they expanded it enough to display its full URL).
I suspect the effectiveness of referrer logs will be sporadic and likely reduced on smartphones and tablets where the apps in use are less likely to have expanded tweets in that way in order to then provide that data to third party websites.
#!/usr/bin/env python3
import requests
import urllib.parse
shorturl = input("Enter the shortened URL in its entirety: ")
r0 = requests.get(shorturl, verify=True)
t0 = "https://twitter.com/search?f=tweets&q="
t1 = urllib.parse.quote_plus(r0.url)
r1 = requests.get("{0}{1}".format(t0, t1), verify=True)
# the results will be in r1.content
# there may be some benefit from cutting the http:// or
# https:// from r0.url before creating the quoted string in t1.
That, however, is as good as it gets ... without paying Twitter for enhanced data access.
Find out which is the original URL the shortened URL is pointing to e.g. by using a service like http://www.getlinkinfo.com
Paste that original URL into Google's search box
If you are specifically looking for references from Twitter do like this: site:twitter.com "https://example.com"
If you use the Twitter search APIs, you can find tweets that mention the t.co URL (if they're visible to you) and find the link that way.
Here’s some Python for doing that, taken from a longer blog post I wrote:
from requests_oauthlib import OAuth1Session
sess = OAuth1Session(
client_key=TWITTER_CONSUMER_KEY,
client_secret=TWITTER_CONSUMER_SECRET,
resource_owner_key=TWITTER_ACCESS_TOKEN,
resource_owner_secret=TWITTER_ACCESS_TOKEN_SECRET
)
def find_tweets_using_tco(tco_url):
"""
Given a shortened t.co URL, return a set of URLs for tweets that use this URL.
"""
# See https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets.html
resp = sess.get(
"https://api.twitter.com/1.1/search/tweets.json",
params={
"q": tco_url,
"count": 100,
"include_entities": True
}
)
statuses = resp.json()["statuses"]
tweet_urls = set()
for status in statuses:
# A retweet shows up as a new status in the Twitter API, but we're only
# interested in the original tweet. If this is a retweet, look through
# to the original.
try:
tweet = status["retweeted_status"]
except KeyError:
tweet = status
# If this tweet shows up in the search results for a reason other than
# "it has this t.co URL as a short link", it's not interesting.
if not any(u["url"] == tco_url for u in tweet["entities"]["urls"]):
continue
url = "https://twitter.com/%s/status/%s" % (
tweet["user"]["screen_name"], tweet["id_str"]
)
tweet_urls.add(url)
return tweet_urls
Twitter's t.co URL shortener simply redirects to another URL in the HTTP response. To find that other URL, you only need to fetch the t.co URL and look at the location header in the response. curl can do this:
curl -v <t.co URL>
To extract only the URL from all that information, you can use:
curl -w "%{redirect_url}" <t.co URL>
The -w option tells curl to output only the redirect_url variable.
List of tweets that referred to your pages is available under Social networks and then Trackbacks menu directly in Google Analytics.
This is how you find the original tweet:
Click the t.co link to find the original URL
Go to https://twitter.com/explore (#)
Copy and paste the link into the on "search twitter" search box
You will see the tweet(s) with the link

Get request part after hash sign

My web-site has AJAX-powered search, that uses deep-linking. When user follows a link …
http://example.com/articles#/?tags=Mac%20OS,review
… tags "Mac OS" and "review" should already been selected in a search form and articles, related to "Mac OS" and "review" should be presented on the page.
I have following scenario, that a need to fix
User follows the link http://example.com/articles#/?tags=Mac%20OS
During initial page rendering, all articles are fetched
On the client side, hash-part is parsed and only "Mac OS"-related articles are requested via AJAX.
Client receives "Mac OS"-articles and replaces all articles, fetched at step 2. Also it marks "Mac OS" tag as selected on a search-form.
The problem here - is duplicated articles rendering, that looks really bad for the user. He looks at all articles, and after couple of seconds, they will be replaced with "Mac OS"-articles.
I need to have following scenario:
User follows the link http://example.com/articles#/?tags=Mac%20OS
Server parses hash-part and returns "Mac OS"-related articles
Client understands, that "Mac OS"-articles are already there and does nothing. It just marks "Mac OS" tag as selected.
To do this, i need to get hash-part of the request string:
/?tags=Mac%20OS
I cannot use request parameters after ?, because i use AJAX and deep-linking. With ?-part, browser will be forced to reload the page. I need to do anything without reloading the page.
You help will be greatly appreciated.
Thanks.
The part of a URL after the hash is not sent to the server, so you can't process it there. You can extract that part of the URL in the client-side code that creates your Ajax request and send it as a parameter.
#NickFitz is correct, but if you must send whatever comes after the # hash/pound symbol, you can use the URL encoded characters that represent # which is %23.
So %23 and whatever that comes after %23 will be sent to the server. If you are using modern web server, they will automatically recognize that %23 is #. In Ruby on Rails, Rack does this for you.

Resources