Permalink
Browse files

Initial import of plugin.

  • Loading branch information...
0 parents commit 782e529bf4a0594e1d67404c30a0ce3282a5e8b7 @nbibler committed May 21, 2008
Showing with 552 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +20 −0 MIT-LICENSE
  3. +11 −0 README
  4. +22 −0 Rakefile
  5. 0 init.rb
  6. +128 −0 lib/devpay.rb
  7. +31 −0 lib/devpay/constants.rb
  8. +47 −0 lib/devpay/errors.rb
  9. +60 −0 test/activation_test.rb
  10. +64 −0 test/purchase_url_test.rb
  11. +31 −0 test/test_helper.rb
  12. +137 −0 vendor/ls.rb
@@ -0,0 +1 @@
+rdoc
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Nathaniel E. Bibler
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 README
@@ -0,0 +1,11 @@
+== Devpay
+
+This Devpay plugin is designed to ease integration with
+{Amazon's DevPay}[http://www.amazon.com/DevPay-AWS-Service-Pricing/b/ref=sc_fe_l_3?ie=UTF8&node=342429011]
+services, specifically for web-hosted DevPay products.
+
+DevPay products for the desktop will very likely not find this plugin terribly
+useful. Sorry.
+
+
+Copyright (c) 2008 Nathaniel E. Bibler, released under the MIT license
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the devpay plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the devpay plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'Devpay'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
No changes.
@@ -0,0 +1,128 @@
+require 'devpay/errors'
+require 'devpay/constants'
+require File.dirname(__FILE__) + '/../vendor/ls'
+
+##
+# Manages interactions with the Amazon DevPay system.
+#
+module Devpay
+
+ # Amazon Access Key ID
+ mattr_accessor :access_key_id
+
+ # Amazon Secret Access Key
+ mattr_accessor :secret_access_key
+
+ ##
+ # Returns a fully-qualified URL with the given offer code. The +offer_code+
+ # parameter may be either a +String+ (Amazon offer code) or an object which
+ # responds to an +offer_code+ method call.
+ #
+ # ===== What happens next?
+ #
+ # When the user successfully purchases the product, they will be redirected
+ # back to your site (to the url provided by you when you registered
+ # {your DevPay product}[http://aws.amazon.com/devpayactivity]) with
+ # query string parameters containing the Activation Key and purchased
+ # Product Code.
+ #
+ # ===== Exceptions
+ #
+ # Devpay::Errors::InvalidOfferCode:: If the given or retrieved offer code is not valid.
+ #
+ def self.purchase_url_for(offer_code)
+ offer_code = offer_code.offer_code if offer_code.respond_to?(:offer_code)
+ raise(Errors::InvalidOfferCode, "Invalid offer code given: #{offer_code.inspect}") unless valid_offer_code?(offer_code)
+ Constants::PURCHASE_URL + offer_code
+ end
+
+ ##
+ # Contacts the Amazon License Service to activate the given
+ # +activation_key+ for the given +product_token+ and returns a User Token
+ # for the customer.
+ #
+ # <b>The User Token should be permenantly stored and associated with
+ # your customer's records.</b> It is your responsibility to design your
+ # site so that it can recognize each customer an retrieve the user token
+ # associated with that customer.
+ #
+ # Amazon also suggests that you encrypt the token prior to storage.
+ #
+ # "If the user token is ever missing, the product must get a new one." -- Amazon
+ #
+ # ===== Parameters
+ #
+ # The +activation_key+ should have been received either directly from
+ # Amazon or have been provided to you by your customer. The +product_token+
+ # was provided to you when you registered your DevPay product.
+ #
+ # The +product_token+ parameter can either be a +String+ containing the
+ # token, or an object which responds to +product_token+.
+ #
+ # ===== Hosted DevPay products only
+ #
+ # This method will only activate 'hosted' DevPay products. This should not
+ # be used for 'desktop' DevPay products.
+ #
+ # ===== Exceptions
+ #
+ # Devpay::Errors::InvalidProductToken:: If the given or retrieved product token is not valid.
+ # Devpay::Errors::LicenseServiceError:: If an error occurs when contacting the Amazon License Service.
+ #
+ def self.activate!(activation_key, product_token, access_key_id = @@access_key_id, secret_access_key = @@secret_access_key)
+ product_token = product_token.product_token if product_token.respond_to?(:product_token)
+ raise(Errors::InvalidProductToken, "Invalid product token given: #{product_token.inspect}") unless valid_product_token?(product_token)
+ raise(Errors::InvalidActivationKey, "Invalid activation key given: #{activation_key.inspect}") unless valid_activation_key?(activation_key)
+
+ begin
+ license_service.activate_hosted_product(
+ activation_key,
+ product_token,
+ access_key_id,
+ secret_access_key
+ )
+ rescue RuntimeError => e
+ raise(Errors::LicenseServiceError, e.message, e.backtrace)
+ end
+ end
+
+
+ private
+
+
+ ##
+ # Returns +true+ if the given code is a valid Amazon offer code.
+ #
+ def self.valid_offer_code?(code)
+ code =~ Constants::OFFER_CODE_FORMAT
+ end
+
+ ##
+ # Returns +true+ if the given token is a valid Amazon product token.
+ #
+ def self.valid_product_token?(token)
+ token =~ Constants::PRODUCT_TOKEN_FORMAT
+ end
+
+ ##
+ # Returns +true+ if the given code is a valid Amazon product code.
+ #
+ def self.valid_product_code?(code)
+ code =~ Constants::PRODUCT_CODE_FORMAT
+ end
+
+ ##
+ # Returns +true+ if the given key is a valid Amazon activation key.
+ #
+ def self.valid_activation_key?(key)
+ key =~ Constants::ACTIVATION_KEY_FORMAT
+ end
+
+ ##
+ # Returns a new instance of an Amazon License Service object.
+ #
+ def self.license_service
+ DevPay::LicenseService.new
+ end
+
+end
@@ -0,0 +1,31 @@
+module Devpay
+
+ ##
+ # Contains the majority of the constants utilized by the Devpay plugin.
+ #
+ module Constants
+
+ ##
+ # Character (byte) length of the Amazon product code
+ #
+ PRODUCT_CODE_LENGTH = 8
+
+ ##
+ # Character (byte) length of the Amazon offer code
+ #
+ OFFER_CODE_LENGTH = 8
+
+ PRODUCT_CODE_FORMAT = /\A[\w]{#{Constants::PRODUCT_CODE_LENGTH}}\Z/
+ OFFER_CODE_FORMAT = /\A[\w]{#{Constants::OFFER_CODE_LENGTH}}\Z/
+ PRODUCT_TOKEN_FORMAT = /\A\{ProductToken\}.+\Z/
+ USER_TOKEN_FORMAT = /\A\{UserToken\}.+\Z/
+ ACTIVATION_KEY_FORMAT = /\A[\w]+\Z/
+
+ ##
+ # The basic Amazon DevPay purchase url (without offeringCode)
+ #
+ PURCHASE_URL = 'https://aws-portal.amazon.com/gp/aws/user/subscription/index.html?offeringCode='
+
+ end
+
+end
@@ -0,0 +1,47 @@
+module Devpay
+
+ ##
+ # This is a catch-all error for anything raised through the Devpay plugin.
+ # This will allow you to query for specific errors raised, or anything
+ # raised, at all.
+ #
+ # begin
+ # Devpay.erring.call
+ # rescue Devpay::SpecificError
+ # .. do something specifically useful ..
+ # rescue Devpay::Error
+ # .. do something generally useful that tripped something other than SpecificError ..
+ # end
+ #
+ class Error < Exception; end
+
+ module Errors #:nodoc:
+
+ ##
+ # Raised when a method using an offer code receives an invalid code.
+ #
+ class InvalidOfferCode < Devpay::Error; end
+
+ ##
+ # Raised when a method using the product code receives an invalid code.
+ #
+ class InvalidProductCode < Devpay::Error; end
+
+ ##
+ # Raised when a method using the product token receives an invalid token.
+ #
+ class InvalidProductToken < Devpay::Error; end
+
+ ##
+ # Raised when a method using an activation key receives and invalid key.
+ #
+ class InvalidActivationKey < Devpay::Error; end
+
+ ##
+ # Raised when an error occurs when dealing with the License Service
+ #
+ class LicenseServiceError < Devpay::Error; end
+
+ end
+
+end
@@ -0,0 +1,60 @@
+require 'test_helper'
+
+class ActivationTest < Test::Unit::TestCase
+
+ TEST_PRODUCT_TOKEN = "{ProductToken}b#q.079EUWQu;hsG2b0O3im<Ue=N9gum3UnLXNrrvd/ii0f5/y-MfnM:i7U+cWpOlxHxtWWa7KiAP$8U9+81ec3m89p4qvbY%h-IL_nJk36b8LHZly~TG3oZMhVMa'~HwAw3m$JO`bCP03f85sj4shHD2NANSZOyNWCQ5n>c#VCP[lF<Ce2az4Qh7m8-KI4d8pR.05]H7;OZYN{Jg{o=2ja51CS4EzlMEl77Zmh3EySvx4>G3CKbsRQ&gQ-T4gV4uk1!luzndC8N$2.w!M0UsqViczlPyfs6c5P8&Oacj6@Ibderfklpoiu="
+ TEST_ACTIVATION_KEY = "AC6PMWXPBRPDDB426RW4X76I2MXQ"
+ TEST_USER_TOKEN = "{UserToken}AAMHVXNlclRrbvclYiO3ipJOw3Bw2iIvWRGdDvrMV87ixFvPs0JYxLc3NHofLYf5azDvSQMhme/KbT4xknH0vhg7NMgJFq1OVe9C2jUMMoL8U2uwCj58QfQNlTHCXLUT5Pz4+cmd/9lKrdc8W3COBzg6SLbrjCev57WlIsmmLbD59UrrRfLzyfBlOHbbMyIW6wE/9dF54tmu2XKI7W6VMEpflQXZs4YCjkOmQM6AOQJXTBvq9QJqSL3dkbjsWzvay5XlRHSNgQkWfbm5NYEYBHtM3bO4iWNGlIO8bPKE2Jfu8BZ6Mpy7qSluOXgs8atZnk2PXbQA+MPvSZcsgcDn/2P+wNSBsk45vGEQ167gnPhrWPo3h5XrazaS8xkLldBRczBpPNDVoe2NEg=="
+ TEST_PID = "PPHUXKJYQBLH753XI5BBW5DMW54"
+
+ context "Product activation (activate!)" do
+
+ setup do
+ @product = Product.new
+ @ls = mock('License Service')
+ @product.stubs(:product_token).returns(TEST_PRODUCT_TOKEN)
+ Devpay.stubs(:license_service).returns(@ls)
+ end
+
+ context "in general" do
+
+ context "the license service" do
+
+ setup do
+ Devpay.expects(:license_service).returns(@ls)
+ end
+
+ should "be used" do
+ @ls.stubs(:activate_hosted_product).with(any_parameters).returns(TEST_USER_TOKEN)
+ Devpay.activate!(TEST_ACTIVATION_KEY, TEST_PRODUCT_TOKEN)
+ end
+
+ should "be passed the activation key" do
+ @ls.expects(:activate_hosted_product).with(TEST_ACTIVATION_KEY, anything, anything, anything).returns(TEST_USER_TOKEN)
+ Devpay.activate!(TEST_ACTIVATION_KEY, TEST_PRODUCT_TOKEN)
+ end
+
+ should "be passed the product token" do
+ @ls.expects(:activate_hosted_product).with(anything, TEST_PRODUCT_TOKEN, anything, anything).returns(TEST_USER_TOKEN)
+ Devpay.activate!(TEST_ACTIVATION_KEY, TEST_PRODUCT_TOKEN)
+ end
+
+ context "when a problem occurs" do
+
+ setup do
+ @ls.stubs(:activate_hosted_product).with(any_parameters).raises(RuntimeError, 'Test Exception')
+ end
+
+ should "raise a LicenseServiceError" do
+ assert_raise(Devpay::Errors::LicenseServiceError) { Devpay.activate!(TEST_ACTIVATION_KEY, TEST_PRODUCT_TOKEN) }
+ end
+
+ end
+
+ end
+
+ end
+
+ end
+
+end
@@ -0,0 +1,64 @@
+require 'test_helper'
+
+class PurchaseUrlTest < Test::Unit::TestCase
+
+ context "The purchase url (purchase_url_for)" do
+
+ setup do
+ @product = Product.new
+ @product.stubs(:offer_code).returns("ABCD1234")
+ end
+
+ context "in general" do
+
+ should "use HTTPS" do
+ assert_match /\Ahttps:\/\//, Devpay.purchase_url_for(@product)
+ end
+
+ should "link to Amazon's aws-portal" do
+ assert_match /aws-portal\.amazon\.com/, Devpay.purchase_url_for(@product)
+ end
+
+ should "link to the proper location" do
+ assert_match /\/gp\/aws\/user\/subscription\/index\.html/, Devpay.purchase_url_for(@product)
+ end
+
+ should "contain an offeringCode parameter" do
+ assert_match /\?.*offeringCode=/, Devpay.purchase_url_for(@product)
+ end
+
+ end
+
+ context "when given an object" do
+
+ should "contain the object's offer code" do
+ @product.expects(:offer_code).returns("ABCD1234")
+ assert_match /\?.*offeringCode=ABCD1234/, Devpay.purchase_url_for(@product)
+ end
+
+ context "that doesn't respond to offer code" do
+ should "raise InvalidOfferCode" do
+ assert_raise(Devpay::Errors::InvalidOfferCode) { Devpay.purchase_url_for(Hash) }
+ end
+ end
+
+ end
+
+ context "when given a string" do
+
+ should "use the string as the offer code" do
+ assert_match /\?.*offeringCode=1234ABCD/, Devpay.purchase_url_for("1234ABCD")
+ end
+
+ context "that is not valid" do
+ should "raise InvalidOfferCode" do
+ assert_raise(Devpay::Errors::InvalidOfferCode) { Devpay.purchase_url_for("ab") }
+ end
+ end
+
+ end
+
+ end
+
+
+end
Oops, something went wrong.

0 comments on commit 782e529

Please sign in to comment.