From 6b2fbeae01b6b0d331147ded182d1914cedfb08a Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 19 May 2016 01:18:15 -0300 Subject: [PATCH] Real creation of gift card --- .gitignore | 4 + Gruntfile.js | 7 +- public/views/amazon.html | 2 +- src/js/controllers/buyAmazon.js | 9 +- src/js/services/amazonService.js | 148 +++++++++++++++++++++++-------- src/sass/main.scss | 6 +- util/amazon.js | 34 +++++++ 7 files changed, 164 insertions(+), 46 deletions(-) create mode 100755 util/amazon.js diff --git a/.gitignore b/.gitignore index 4a30d65d8..eeedbc84b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,10 @@ src/js/translations.js coinbase.json src/js/coinbase.js +# Amazon.com API credentials +amazon.json +src/js/amazon.js + # version src/js/version.js diff --git a/Gruntfile.js b/Gruntfile.js index 3fd51b784..f43f545f5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -34,6 +34,9 @@ module.exports = function(grunt) { coinbase: { command: 'node ./util/coinbase.js' }, + amazon: { + command: 'node ./util/amazon.js' + }, clear: { command: 'rm -Rf bower_components node_modules' }, @@ -105,6 +108,7 @@ module.exports = function(grunt) { 'bower_components/angular-sanitize/angular-sanitize.js', 'bower_components/ng-csv/build/ng-csv.js', 'bower_components/angular-mocks/angular-mocks.js', + 'bower_components/crypto-js/crypto-js.js', 'angular-bitcore-wallet-client/angular-bitcore-wallet-client.js' ], dest: 'public/lib/angular.js' @@ -121,6 +125,7 @@ module.exports = function(grunt) { 'src/js/translations.js', 'src/js/version.js', 'src/js/coinbase.js', + 'src/js/amazon.js', 'src/js/init.js', 'src/js/trezor-url.js', 'bower_components/trezor-connect/login.js' @@ -266,7 +271,7 @@ module.exports = function(grunt) { } }); - grunt.registerTask('default', ['nggettext_compile', 'exec:version', 'exec:coinbase', 'browserify', 'sass', 'concat', 'copy:icons', 'copy:ionic_fonts']); + grunt.registerTask('default', ['nggettext_compile', 'exec:version', 'exec:coinbase', 'exec:amazon', 'browserify', 'sass', 'concat', 'copy:icons', 'copy:ionic_fonts']); grunt.registerTask('prod', ['default', 'uglify']); grunt.registerTask('translate', ['nggettext_extract']); grunt.registerTask('test', ['karma:unit']); diff --git a/public/views/amazon.html b/public/views/amazon.html index 5f14bd234..cd57f6ff9 100644 --- a/public/views/amazon.html +++ b/public/views/amazon.html @@ -17,7 +17,7 @@

- Amazon Gift Card + Amazon.com Gift Card

diff --git a/src/js/controllers/buyAmazon.js b/src/js/controllers/buyAmazon.js index 4735eb94c..a4e2da7b8 100644 --- a/src/js/controllers/buyAmazon.js +++ b/src/js/controllers/buyAmazon.js @@ -105,9 +105,10 @@ angular.module('copayApp.controllers').controller('buyAmazonController', this.createTx = function() { self.error = null; + var currency_code = configService.getSync().amazon.testnet ? window.amazon_sandbox_currency_code : window.amazon_currency_code; var dataSrc = { price: $scope.fiat, - currency: 'USD' + currency: currency_code }; var outputs = []; var config = configService.getSync(); @@ -129,7 +130,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', address = data.data.bitcoinAddress; amount = parseInt((data.data.btcPrice * 100000000).toFixed(0)); - comment = 'Buy Amazon Gift Card'; + comment = 'Amazon.com Gift Card'; outputs.push({ 'toAddress': address, @@ -172,8 +173,8 @@ angular.module('copayApp.controllers').controller('buyAmazonController', bitpayInvoiceId: data.data.id, bitpayInvoiceUrl: data.data.url }; - self.loading = 'Buying gift card...'; - amazonService.buyGiftCard(gift, function(err, giftCard) { + self.loading = 'Creating gift card...'; + amazonService.createGiftCard(gift, function(err, giftCard) { self.loading = null; if (err) { self.error = err; diff --git a/src/js/services/amazonService.js b/src/js/services/amazonService.js index ff6435e54..b32411a49 100644 --- a/src/js/services/amazonService.js +++ b/src/js/services/amazonService.js @@ -1,46 +1,52 @@ 'use strict'; -angular.module('copayApp.services').factory('amazonService', function($http, $log, isCordova, lodash, storageService, configService) { +angular.module('copayApp.services').factory('amazonService', function($http, $log, isCordova, lodash, moment, storageService, configService) { var root = {}; var credentials = {}; - var fakeData = { - "cardInfo": { - "cardNumber":null, - "cardStatus":"RefundedToPurchaser", - "expirationDate":null, - "value":{ - "amount":1.0, - "currencyCode":"USD" - } - }, - "creationRequestId":"AwssbTSpecTest001", - "gcClaimCode":"Z7NV-LBBG39-75MU", - "gcExpirationDate":null, - "gcId":"A2GCN9BRX5QS76", - "status":"SUCCESS", - "bitpayInvoiceId":"NJtevvEponHbQVmYoL7FYp", - "bitpayInvoiceUrl":"http://test.bitpay.com/invoice?id=XwrLryQEypTKg4nq37t3bN" - }; - root.setCredentials = function(network) { + credentials.AMAZON_SANDBOX = network == 'testnet' ? true : false; + credentials.AMAZON_SERVICE_NAME = 'AGCODService'; if (network == 'testnet') { - credentials.BITPAY_API = 'https://test.bitpay.com'; - credentials.BITPAY_API_TOKEN = 'GDtYwBqbMZvjz5JrYZ1d2ba96StV92U4Yg4AGhT3C4He'; - credentials.AMAZON_HOST = 'https://agcod-v2-gamma.amazon.com'; + credentials.BITPAY_API_URL = window.amazon_sandbox_bitpay_api_url; + credentials.BITPAY_API_TOKEN = window.amazon_sandbox_bitpay_api_token; + credentials.AMAZON_ACCESS_KEY = window.amazon_sandbox_access_key; + credentials.AMAZON_SECRET_KEY = window.amazon_sandbox_secret_key; + credentials.AMAZON_PARTNER_ID = window.amazon_sandbox_partner_id; + credentials.AMAZON_REGION = window.amazon_sandbox_region; + credentials.AMAZON_ENDPOINT = window.amazon_sandbox_endpoint; } else { - credentials.BITPAY_API = 'https://bitpay.com'; - credentials.BITPAY_API_TOKEN = window.bitpay_token; - credentials.AMAZON_HOST = 'https://agcod-v2.amazon.com'; + credentials.BITPAY_API_URL = window.amazon_bitpay_api_url; + credentials.BITPAY_API_TOKEN = window.amazon_bitpay_api_token; + credentials.AMAZON_ACCESS_KEY = window.amazon_access_key; + credentials.AMAZON_SECRET_KEY = window.amazon_secret_key; + credentials.AMAZON_PARTNER_ID = window.amazon_partner_id; + credentials.AMAZON_REGION = window.amazon_region; + credentials.AMAZON_ENDPOINT = window.amazon_endpoint; }; }; + var _getSignatureKey = function() { + + var key = credentials.AMAZON_SECRET_KEY; + var dateStamp = moment.utc().format('YYYYMMDD'); + var regionName = credentials.AMAZON_REGION; + var serviceName = credentials.AMAZON_SERVICE_NAME; + + var kDate= CryptoJS.HmacSHA256(dateStamp, "AWS4" + key, { asBytes: true}); + var kRegion= CryptoJS.HmacSHA256(regionName, kDate, { asBytes: true }); + var kService=CryptoJS.HmacSHA256(serviceName, kRegion, { asBytes: true }); + var kSigning= CryptoJS.HmacSHA256("aws4_request", kService, { asBytes: true }); + + return kSigning; + } + var _getBitPay = function(endpoint) { return { method: 'GET', - url: credentials.BITPAY_API + endpoint, + url: credentials.BITPAY_API_URL + endpoint, headers: { 'content-type': 'application/json' } @@ -51,7 +57,7 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo data.token = credentials.BITPAY_API_TOKEN; return { method: 'POST', - url: credentials.BITPAY_API + endpoint, + url: credentials.BITPAY_API_URL + endpoint, headers: { 'content-type': 'application/json' }, @@ -116,17 +122,81 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo }); }; - root.buyGiftCard = function(gift, cb) { - var newId = Math.floor(Date.now() / 1000); - var saveData = fakeData; - saveData.gcId = saveData.gcId + '' + newId; - saveData.cardInfo.value.amount = gift.amount; - saveData.cardInfo.value.currencyCode = gift.currencyCode; - saveData['bitpayInvoiceId'] = gift.bitpayInvoiceId; - saveData['bitpayInvoiceUrl'] = gift.bitpayInvoiceUrl; - saveData['date'] = newId; - root.saveGiftCard(saveData, null, function(err) { - return cb(null, fakeData); + root.createGiftCard = function(dataSrc, cb) { + var sandbox = credentials.AMAZON_SANDBOX ? 'T' : 'P'; // T: test - P: production + var now = moment().unix(); + var requestId = credentials.AMAZON_PARTNER_ID + sandbox + now; + + var data = { + 'creationRequestId': requestId, + 'partnerId': credentials.AMAZON_PARTNER_ID, + 'value': { + 'currencyCode': dataSrc.currencyCode, + 'amount': dataSrc.amount + } + }; + + var content_type = 'application/json'; + var accept = 'application/json'; + var amz_date = moment.utc().format('YYYYMMDD[T]HHmmss[Z]'); + var date_stamp = moment.utc().format('YYYYMMDD'); + var amz_target = 'com.amazonaws.agcod.AGCODService.CreateGiftCard'; + var canonical_querystring = ''; + + /************* TASK 1: CREATE A CANONICAL REQUEST *************/ + + var canonical_headers = + 'accept:' + accept + '\n' + + 'content-type:' + content_type + '\n' + + 'host:' + credentials.AMAZON_ENDPOINT.replace('https://', '') + '\n' + + 'x-amz-date:' + amz_date + '\n' + + 'x-amz-target:' + amz_target + '\n'; + + var signed_headers = 'accept;content-type;host;x-amz-date;x-amz-target'; + data = JSON.stringify(data); + var payload_hash = CryptoJS.SHA256(data).toString(CryptoJS.enc.Hex); + var canonical_request = 'POST' + '\n' + '/CreateGiftCard' + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash; + + /************* TASK 2: CREATE THE STRING TO SIGN *************/ + + var algorithm = 'AWS4-HMAC-SHA256'; + var credential_scope = date_stamp + '/' + credentials.AMAZON_REGION + '/' + credentials.AMAZON_SERVICE_NAME + '/' + 'aws4_request'; + var hashed_canonical_request = CryptoJS.SHA256(canonical_request).toString(CryptoJS.enc.Hex); + var string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashed_canonical_request; + + /************* TASK 3: CALCULATE THE SIGNATURE *************/ + + var signing_key = _getSignatureKey(); + var signature = CryptoJS.HmacSHA256(string_to_sign, signing_key).toString(CryptoJS.enc.Hex) + var authorization_header = algorithm + ' ' + 'Credential=' + credentials.AMAZON_ACCESS_KEY + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature; + + /************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************/ + + var headers = { + 'Content-Type': content_type, + 'Accept': accept, + 'X-Amz-Date': amz_date, + 'X-Amz-Target': amz_target, + 'Authorization': authorization_header + }; + + $http({ + 'method': 'POST', + 'url': credentials.AMAZON_ENDPOINT + '/CreateGiftCard', + 'data': data, + 'headers': headers + }).then(function(data) { + $log.info('Amazon Create Gift Card: SUCCESS'); + var newData = data.data; + newData['bitpayInvoiceId'] = dataSrc.bitpayInvoiceId; + newData['bitpayInvoiceUrl'] = dataSrc.bitpayInvoiceUrl; + newData['date'] = now; + root.saveGiftCard(newData, null, function(err) { + return cb(null, newData); + }); + }, function(data) { + $log.error('Amazon Create Gift Card: ERROR ' + data.statusText); + return cb(data.statusText); }); }; diff --git a/src/sass/main.scss b/src/sass/main.scss index 02bcdbd34..73be3a3fb 100644 --- a/src/sass/main.scss +++ b/src/sass/main.scss @@ -536,6 +536,10 @@ ul.manage li { font-size: 24px; } +.size-28 { + font-size: 28px; +} + .size-36 { font-size: 36px; } @@ -1655,7 +1659,7 @@ a.missing-copayers { .sidebar { background: #2C3E50; .icon { - width: 39px; + width: 35px; text-align: center; margin-right: 15px; float: left; diff --git a/util/amazon.js b/util/amazon.js new file mode 100755 index 000000000..be6a1e008 --- /dev/null +++ b/util/amazon.js @@ -0,0 +1,34 @@ +#!/usr/bin/env node + +'use strict'; + +var fs = require('fs'); +var file; + +try { + file = fs.readFileSync('./amazon.json', 'utf8'); +} catch(err) { + return; +} + +var json = JSON.parse(file); +console.log('Amazon Partner ID: ' + json.production.partner_id); + +var content = 'window.amazon_sandbox_access_key="' + json.sandbox.access_key + '";'; +content = content + '\nwindow.amazon_sandbox_secret_key="' + json.sandbox.secret_key + '";'; +content = content + '\nwindow.amazon_sandbox_partner_id="' + json.sandbox.partner_id + '";'; +content = content + '\nwindow.amazon_sandbox_currency_code="' + json.sandbox.currency_code + '";'; +content = content + '\nwindow.amazon_sandbox_region="' + json.sandbox.region + '";'; +content = content + '\nwindow.amazon_sandbox_endpoint="' + json.sandbox.endpoint + '";'; +content = content + '\nwindow.amazon_sandbox_bitpay_api_token="' + json.sandbox.bitpay_api_token + '";'; +content = content + '\nwindow.amazon_sandbox_bitpay_api_url="' + json.sandbox.bitpay_api_url + '";'; +content = content + '\nwindow.amazon_access_key="' + json.production.access_key + '";'; +content = content + '\nwindow.amazon_secret_key="' + json.production.secret_key + '";'; +content = content + '\nwindow.amazon_partner_id="' + json.production.partner_id + '";'; +content = content + '\nwindow.amazon_currency_code="' + json.production.currency_code + '";'; +content = content + '\nwindow.amazon_region="' + json.production.region + '";'; +content = content + '\nwindow.amazon_endpoint="' + json.production.endpoint + '";'; +content = content + '\nwindow.amazon_bitpay_api_token="' + json.production.bitpay_api_token + '";'; +content = content + '\nwindow.amazon_bitpay_api_url="' + json.production.bitpay_api_url + '";'; +fs.writeFileSync("./src/js/amazon.js", content); +