SendOwl License API


#1

Hi, I am currently testing SendOwl for selling my extensions but I can’t figure out how to integrate their license API.

They suggest using curl…When I use the line below in my terminal it works and gives me an xml but how can I use it in SketchUp?

curl -H "Accept: text/xml" https://key:secret@www.sendowl.com/api/v1/products/productId/licenses/check_valid?key=licenseKeyToCheck

There is a website which converts curl to ruby…https://jhawthorn.github.io/curl-to-ruby/

If I put the curl string above it gives me the following but not sure how to use it.

require 'net/http'
require 'uri'

uri = URI.parse("https://key:secret@www.sendowl.com/api/v1/products/productId/licenses/check_valid?key=licenseKeyToCheck")
request = Net::HTTP::Get.new(uri)
request["Accept"] = "text/xml"

req_options = {
  use_ssl: uri.scheme == "https",
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

# response.code
# response.body

Any help would be appreciated!

Note: the examples above I don’t have my account keys or real product id or license numbers for obvious reasons…Cheers!


#2

Where is the question? How to use the xml from SendOwl, or how to do the request?


#3

Did you see the examples I posted here …

?

You can use a callback block with http.request() ie …

http.request(request_object) do |response|
  my_parse_xml_method( response.body )
end

Using SSL for http is an issue inside SketchUp Ruby.

As Andreas says use the Sketchup::Http classes if possible as they do not use the Ruby OpenSSL lib.

@thomthom said at GitHub API issue tracker

One of the main issues with Net::HTTP stems from OpenSSL. When OpenSSL is initiated for the first time it can cause a significant lag in SU. Anything from half a minute to half and hour+. Seems to depend on how much memory the SU app have used that session.

Another issue would be if you needed not to block the main thread, since Ruby threads doesn’t work properly inside of SU. So it’s tricky to do async HTTP requests.


#4

No, but I am new to dealing with xml…maybe json is easier?

Here is were I am at…

require 'uri'

# Setup variables
key = ''
secret = ''
productId = ''
licenseKeyToCheck = ''

# Perform check
url = "https://#{key}:#{secret}@www.sendowl.com/api/v1/products/#{productId}/licenses/check_valid?key=#{licenseKeyToCheck}"

request = Sketchup::Http::Request.new(url)

request.start do |request, response|
  puts "body: #{response.body}"
end

Ruby Console gives me the following…

"true"
body: Please specify a supported `Accept` header. Valid options: `application/json`, `application/xml

Nope, but I 'll take a look…I am kinda intimidated since I normally don’t deal with this kind of thing.

I have noticed SketchUp freezing for couple seconds when running some test, maybe it is this issue you talk about.

I need to learn how to make a parse method for xml or maybe try a json parser.

By the way I found someone using SendOwl API with PHP but I don’t know PHP :frowning:

// Setup variables
$key = ''; // TODO: replace with your own
$secret = ''; // TODO: replace with your own
$productId = ''; // TODO: replace with your own
$licenseKeyToCheck = ''; // TODO: replace with your own

// Perform check
$url = 'https://' . $key . ':' . $secret . '@www.sendowl.com/api/v1/products/' . $productId . '/licenses/check_valid?key=' . $licenseKeyToCheck;
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_HTTPHEADER, array( 'Accept: text/xml' ) ); // for json use: 'Accept: application/json'
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
$output = curl_exec( $ch );
curl_close($ch);
echo $output;

Cheers!


#5

I’m using SendOwl, but I don’t contact it directly from my extension. I find it too risky because you need the secret key to their service to use their API.

I make requests to my own server, which in turn takes care of checking with SendOwl. (This is done via PHP in my case.)

This allows me to put additional checks in place, such as number of activations etc - so I can track if someone is sharing their serial. That allows me to deactivate a key if I want. It also decouples the extension from directly depending on SendOwl. If I replace SendOwl with another service, I don’t have to update my extension.

The HTTP request I make from my extension to my own server is done in JS, from within the webdialog. Because the user input their serial key into a webdialog - so I can just do it directly there. Saves me from pushing the logic into Ruby. Especially nice since Ruby’s Net::Http lib’s HTTPS connections can be a pain.

I find JSON to be easier to deal with than XML in Ruby. You can just require 'json' and get a Hash+Array structure that is easy to navigate. With XML you need additional library.

That SendOwl response is actually very helpful. Tells you exactly what you are missing. You need to add a header the declare how you want to accept the response.

request = Sketchup::Http::Request.new(url)
request.headers = {
  'Accept' => 'application/json'
}

#6

But be very careful with your secret key, if anyone obtains it they can potentially create their own licenses, or list all known licenses. That’s which I put a layer between my extension and the SendOwl API. My layer in between allows no write access or enumerations.


#7

This will happen if you use the standard library from the console.
But as Thomthom says, the loading of OpenSSL could take 30 minutes !

Does Send Owl insist upon using the HTTPS protocol ?

If not, … if it will work with just plain HTTP use that IF (and only if) you must use the standard Ruby Net::HTTP library classes (say with SketchUp versions earlier than 2017, where the newer API classes are not available.)


Plain text strings are very easy to see in Ruby’s memory, so loading your “secret” strings and having them sit in memory as plain text is not very secure.


So here is where your at now using just the API classes in SU2017+ …
(You’re actually not using URI so I leave this out of the depandancies.)

require 'json'

check_license()

  # Setup variables
  key = ''
  secret = ''
  productId = ''
  licenseKeyToCheck = ''

  # Perform check
  url = "https://#{key}:#{secret}@www.sendowl.com/api/v1/products/"<<
        "#{productId}/licenses/check_valid?key=#{licenseKeyToCheck}"

  @request = Sketchup::Http::Request.new(url)

  @request.headers = {
    'Accept' => 'application/json'
  }

  @request.start do |request, response|
    case response.headers['content-type'].split.first.chomp(';')
    when 'application/json'
      @@license_details = JSON.parse(response.body, symbolize_names: true)
      # @@license_details will be a Ruby hash if successful
    when 'application/xml'
      @@license_details = parse_xml( response.body )
      # Need to use some library like REXML or your choice ...
    when 'text/html'
      @dlg = UI::HtmlDialog.new(
        dialog_title: "SendOwl Response: #{response.status_code}",
        preferences_key: nil,
        scrollable: true,
        resizable: true,
        width: 600,
        height: 400,
      )
      @dlg.set_html( response.body )
      @dlg.show
    else
      puts "body: #{response.body}"
    end
  end

end ###

#8

Another note. Credentials embedded in URIs have been deprecated (at the least) and removed from the web specifications because of security concerns. Most web browsers will no longer allow their use.

If Send Owl allows Basic Authentication, you should try to use that instead.


#9

This works, I am able to get the license details as Ruby hash!

But, I first thought I could encrypt this code and all would be secure…not so sure now.

It also gives me this warning…

"true"
<main>:23: warning: class variable access from toplevel
<main>:25: warning: class variable access from toplevel
body: [{:license=>{:id=>value, :order_id=>value, :product_id=>value, :key=>"value", :order_refunded=>value}}]

Even though I am now able to check if the license is valid directly from SketchUp I am not sure I can use it given the security concerns.

How did you set up your own server?


#10

Remember that Ruby is a very reflective and dynamic language. Once an encrypted RBE is loaded, the code is loaded into the interpreter and there are many ways to poke and inspect the various objects - like strings used, that might contain sensitive data. Any language with a garbage collector will make data stay alive for longer than the execution of the code.

Also, there are various tools meant to debug HTTP traffic, that also allow the administrator of a machine to also inspect HTTPS traffic. This means the secret key passed from the machine could be extracted from the owner of the machine.

I had some PHP experience from before. So I set up a new server for my commercial extensions using Laravel, a PHP framework. Then I used Laravel Forge to help me deploy the website easily by just pushing to a Git repository for the website.

That being said, if you only want to have a license server, you can go for a simpler solution. Find a host that offer any language you prefer, Ruby, PHP, Python… what ever suit your needs. If Ruby is your strong suit, then you might be better off picking a host that allows you to use Ruby. And then you should be able to set up a rather small license server. Just an API endpoint which you call from your extension, then your server makes the SendOwl request on you behalf. This could keep your secret key entirely secured on your own server and not stored in any form on your users’s machine.
I’m not that familiar with Ruby web applications, but Rack might be one solution to quickly set up a webserver: https://rack.github.io/

But this is just a suggestion. I merely wanted to point out potential gotchas in case you were not aware of them. How much effort you want to put into it is up to you.

I’m in favor of not spending too much time on license and anti-piracy measure. Just enough to keep honest people honest. You can ramp up the security if you see it actually being a problem. Otherwise it’s very easy to get lost in bolting on too much security measure without actually getting to the point of delivering a product.


#11

SendOwl docs describe that the API key and secret key is passed via Basic Auth:

However, the CURL example they provide demonstrate authenticating via URL. Probably for convenience in for a short example. But as Dan mentions, it’s deprecated.

But going back to the SendOwl License API, it’s important to read its documentation: https://www.sendowl.com/developers/api/licenses#product-check-valid

IMPORTANT - Do not include calls to this API endpoint in your software. Whilst this will enable you to check license validity directly, it will expose your API key and secret to anyone examining your source code or watching wire data. With your API key and secret somebody could access your order history, remove your products… in short anything this API allows. Instead, to check license data in your software perform a call to your own server, which should in turn make a call to the SendOwl API to check license validity. This ensures only your server has details of your API key/secret. Order name/email can also be checked for additional security by checking the order associated with the license.


#12

Crazy good advice from Thomas !


:roll_eyes:

ALL of our examples are meant to be wrapped WITHIN your author/company namespace module, plugin sub-module (and/or custom classes if needed.)

It is obvious from this warning that the method should not be defined at the top level (in Ruby’s ObjectSpace.)
Ie, a module or class variable is for use within a module or class definition.


#13

Thanks for the help everyone I am very happy with the feedback! :slight_smile:


#14

I know that being in your position right now can be frustrating. You have product and new ideas you want to get to, but you need some form of license activation. While looking for solutions it looks to quickly snowball into a much more complicated solution.

I think that for your initial start you should try to go for simplicity. Get a minimal setup going, which you can release your products with. Then you can slowly expand functionality as needed.

He’s my suggestion for a bare minimum:

Since you write Ruby extension, I’m going to suggest trying to set up a Ruby powered server. (Pick another language if you feel more comfortable with that.)

  1. Get a host for your server. You can probably do with a simple shared hosting that support your chosen server language. This would be doable to obtain very cheaply.
  2. You off course need a domain (you might already have this?)
  3. Set up a very simple HTTP API endpoint on your server, where you accept a serial key (maybe email if you want to double check data) Something like example.com/api/v1/check_license?key=0123-456&email=john@example.com
    (I added v1 to the URL because it makes it easier to deal with older clients that hit your old API)
  4. Find a small framework to serve your responses. In Ruby it looks like Rack might be good starting point. I found this guide: https://gist.github.com/markbates/4240848 It show you how to set up API end points (routes) and how to map them to various actions. With that you make your server call the SendOwl API and return your own custom response. Along that you can add logging if you want. Something you can add later. If you feel the need for it you can expand it to have your extension pass the MAC address of the machine its on, so you can from your server enforce an x number of activation.

If you plan to support SU versions older than SU2017 you need to evaluate whether you want to use Net::Http or do an AJAX call from the JavaScript in a WebDialog. (You might find less hassle with AJAX call from a webdialog.) But even with HTTP requests from JavaScript there are some gotchas, cross site scripting protection. You may have to do your request as a JSONP request to work around that. But all of that are details you have to judge depending on your own requirements.

Have a go at trying to set up a mini-server - keep it simple. Then let us know how it’s going.


#15

A completely different aproach could be to use Extension Warehouse. While it’s quite far from perfect it’s possible to just plug into and get going with actually create new extensions.


#16

I am currently selling some extensions on Extension Warehouse. You and other developers have helped me through that journey. It was not easy but after some persistence, I managed to get the SketchUp Licensing API working.

Now, I want to learn how to license my extensions with SendOwl API because if I want to also sell a software not related to SketchUp I can do so…For example a game.

Yes, it can be frustrating but I also think it is fun to learn how to code. SketchUp has been responsible for me learning how to code and I will keep making extensions. But, I also want to branch out and start learning to code other stuff like games and web apps.

Starting with a minimal viable product is the way to go indeed. I read a book by Eric Ries - The Lean Startup and it talks about the importance of not wasting time developing stuff.

Is Heroku viable? If so I have deployed a simple crud app made with rails already so I am not starting from scratch.

Yes, I have bought domains before with Google domains.

I am new to this but I have already started watching tutorials on Rest and how to make a request to an API.

Thanks for the guide I’ll take a look.

I will thank you very much!


#17

I’m not familiar with Ruby web apps, I’ve been using PHP. If you have something related that you’ll comfortable with, then that’ll work just fine. It’ll probably get you up and running faster than learning a new framework.