Netsuite OAuth Not Working - oauth
I've tried implementing Netsuite's OAuth Example, as illustrated here: https://netsuite.custhelp.com/app/answers/detail/a_id/42165. I've posted it directly below so you don't have to go to the page if you don't want.
Unfortunately, it's not working. I know that I have the correct token and consumer key's and secrets, and the correct account ID. It's giving me a nice error though:
{"error" : {"code" : "INVALID_LOGIN_ATTEMPT", "message" : "Invalid login attempt."}}
I can look in my login audits, and see that it's saying that the signature is invalid. But the code itself looks fine and was provided by Netsuite.
I've also tried some approaches in Node.JS and haven't gotten them working. Any suggestions as to which direction I should go next?
import oauth2 as oauth
import requests
import time
url = "https://rest.netsuite.com/app/site/hosting/restlet.nl?script=992&deploy=1"
token = oauth.Token(key="080eefeb395df81902e18305540a97b5b3524b251772adf769f06e6f0d9dfde5", secret="451f28d17127a3dd427898c6b75546d30b5bd8c8d7e73e23028c497221196ae2")
consumer = oauth.Consumer(key="504ee7703e1871f22180441563ad9f01f3f18d67ecda580b0fae764ed7c4fd38", secret="b36d202caf62f889fbd8c306e633a5a1105c3767ba8fc15f2c8246c5f11e500c")
http_method = "GET"
realm="ACCT123456"
params = {
'oauth_version': "1.0",
'oauth_nonce': oauth.generate_nonce(),
'oauth_timestamp': str(int(time.time())),
'oauth_token': token.key,
'oauth_consumer_key': consumer.key
}
req = oauth.Request(method=http_method, url=url, parameters=params)
signature_method = oauth.SignatureMethod_HMAC_SHA1()
req.sign_request(signature_method, consumer, token)
header = req.to_header(realm)
headery = header['Authorization'].encode('ascii', 'ignore')
headerx = {"Authorization": headery, "Content-Type":"application/json"}
print(headerx)
conn = requests.get("https://rest.netsuite.com/app/site/hosting/restlet.nl?script=992&deploy=1",headers=headerx)
print(conn.text)
I've also implemented a few Node.JS samples (that haven't worked either). Here is one of them (CryptoJS HMAC-SHA1 and HMAC-SHA256 are on top, then the oauth-1.0a library, and then the code provided by Netsuite with a few small changes to make it work (added a hash_function, renamed 'public' to 'key'):
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS=CryptoJS||function(g,l){var e={},d=e.lib={},m=function(){},k=d.Base={extend:function(a){m.prototype=this;var c=new m;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
p=d.WordArray=k.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=l?c:4*a.length},toString:function(a){return(a||n).stringify(this)},concat:function(a){var c=this.words,q=a.words,f=this.sigBytes;a=a.sigBytes;this.clamp();if(f%4)for(var b=0;b<a;b++)c[f+b>>>2]|=(q[b>>>2]>>>24-8*(b%4)&255)<<24-8*((f+b)%4);else if(65535<q.length)for(b=0;b<a;b+=4)c[f+b>>>2]=q[b>>>2];else c.push.apply(c,q);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
32-8*(c%4);a.length=g.ceil(c/4)},clone:function(){var a=k.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],b=0;b<a;b+=4)c.push(4294967296*g.random()|0);return new p.init(c,a)}}),b=e.enc={},n=b.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f<a;f++){var d=c[f>>>2]>>>24-8*(f%4)&255;b.push((d>>>4).toString(16));b.push((d&15).toString(16))}return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f<c;f+=2)b[f>>>3]|=parseInt(a.substr(f,
2),16)<<24-4*(f%8);return new p.init(b,c/2)}},j=b.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f<a;f++)b.push(String.fromCharCode(c[f>>>2]>>>24-8*(f%4)&255));return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f<c;f++)b[f>>>2]|=(a.charCodeAt(f)&255)<<24-8*(f%4);return new p.init(b,c)}},h=b.Utf8={stringify:function(a){try{return decodeURIComponent(escape(j.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return j.parse(unescape(encodeURIComponent(a)))}},
r=d.BufferedBlockAlgorithm=k.extend({reset:function(){this._data=new p.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=h.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,b=c.words,f=c.sigBytes,d=this.blockSize,e=f/(4*d),e=a?g.ceil(e):g.max((e|0)-this._minBufferSize,0);a=e*d;f=g.min(4*a,f);if(a){for(var k=0;k<a;k+=d)this._doProcessBlock(b,k);k=b.splice(0,a);c.sigBytes-=f}return new p.init(k,f)},clone:function(){var a=k.clone.call(this);
a._data=this._data.clone();return a},_minBufferSize:0});d.Hasher=r.extend({cfg:k.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){r.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,d){return(new a.init(d)).finalize(b)}},_createHmacHelper:function(a){return function(b,d){return(new s.HMAC.init(a,
d)).finalize(b)}}});var s=e.algo={};return e}(Math);
(function(){var g=CryptoJS,l=g.lib,e=l.WordArray,d=l.Hasher,m=[],l=g.algo.SHA1=d.extend({_doReset:function(){this._hash=new e.init([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(d,e){for(var b=this._hash.words,n=b[0],j=b[1],h=b[2],g=b[3],l=b[4],a=0;80>a;a++){if(16>a)m[a]=d[e+a]|0;else{var c=m[a-3]^m[a-8]^m[a-14]^m[a-16];m[a]=c<<1|c>>>31}c=(n<<5|n>>>27)+l+m[a];c=20>a?c+((j&h|~j&g)+1518500249):40>a?c+((j^h^g)+1859775393):60>a?c+((j&h|j&g|h&g)-1894007588):c+((j^h^
g)-899497514);l=g;g=h;h=j<<30|j>>>2;j=n;n=c}b[0]=b[0]+n|0;b[1]=b[1]+j|0;b[2]=b[2]+h|0;b[3]=b[3]+g|0;b[4]=b[4]+l|0},_doFinalize:function(){var d=this._data,e=d.words,b=8*this._nDataBytes,g=8*d.sigBytes;e[g>>>5]|=128<<24-g%32;e[(g+64>>>9<<4)+14]=Math.floor(b/4294967296);e[(g+64>>>9<<4)+15]=b;d.sigBytes=4*e.length;this._process();return this._hash},clone:function(){var e=d.clone.call(this);e._hash=this._hash.clone();return e}});g.SHA1=d._createHelper(l);g.HmacSHA1=d._createHmacHelper(l)})();
(function(){var g=CryptoJS,l=g.enc.Utf8;g.algo.HMAC=g.lib.Base.extend({init:function(e,d){e=this._hasher=new e.init;"string"==typeof d&&(d=l.parse(d));var g=e.blockSize,k=4*g;d.sigBytes>k&&(d=e.finalize(d));d.clamp();for(var p=this._oKey=d.clone(),b=this._iKey=d.clone(),n=p.words,j=b.words,h=0;h<g;h++)n[h]^=1549556828,j[h]^=909522486;p.sigBytes=b.sigBytes=k;this.reset()},reset:function(){var e=this._hasher;e.reset();e.update(this._iKey)},update:function(e){this._hasher.update(e);return this},finalize:function(e){var d=
this._hasher;e=d.finalize(e);d.reset();return d.finalize(this._oKey.clone().concat(e))}})})();
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS=CryptoJS||function(h,s){var f={},g=f.lib={},q=function(){},m=g.Base={extend:function(a){q.prototype=this;var c=new q;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
r=g.WordArray=m.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=s?c:4*a.length},toString:function(a){return(a||k).stringify(this)},concat:function(a){var c=this.words,d=a.words,b=this.sigBytes;a=a.sigBytes;this.clamp();if(b%4)for(var e=0;e<a;e++)c[b+e>>>2]|=(d[e>>>2]>>>24-8*(e%4)&255)<<24-8*((b+e)%4);else if(65535<d.length)for(e=0;e<a;e+=4)c[b+e>>>2]=d[e>>>2];else c.push.apply(c,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
32-8*(c%4);a.length=h.ceil(c/4)},clone:function(){var a=m.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],d=0;d<a;d+=4)c.push(4294967296*h.random()|0);return new r.init(c,a)}}),l=f.enc={},k=l.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++){var e=c[b>>>2]>>>24-8*(b%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b+=2)d[b>>>3]|=parseInt(a.substr(b,
2),16)<<24-4*(b%8);return new r.init(d,c/2)}},n=l.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++)d.push(String.fromCharCode(c[b>>>2]>>>24-8*(b%4)&255));return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b++)d[b>>>2]|=(a.charCodeAt(b)&255)<<24-8*(b%4);return new r.init(d,c)}},j=l.Utf8={stringify:function(a){try{return decodeURIComponent(escape(n.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return n.parse(unescape(encodeURIComponent(a)))}},
u=g.BufferedBlockAlgorithm=m.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=j.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,d=c.words,b=c.sigBytes,e=this.blockSize,f=b/(4*e),f=a?h.ceil(f):h.max((f|0)-this._minBufferSize,0);a=f*e;b=h.min(4*a,b);if(a){for(var g=0;g<a;g+=e)this._doProcessBlock(d,g);g=d.splice(0,a);c.sigBytes-=b}return new r.init(g,b)},clone:function(){var a=m.clone.call(this);
a._data=this._data.clone();return a},_minBufferSize:0});g.Hasher=u.extend({cfg:m.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){u.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(c,d){return(new a.init(d)).finalize(c)}},_createHmacHelper:function(a){return function(c,d){return(new t.HMAC.init(a,
d)).finalize(c)}}});var t=f.algo={};return f}(Math);
(function(h){for(var s=CryptoJS,f=s.lib,g=f.WordArray,q=f.Hasher,f=s.algo,m=[],r=[],l=function(a){return 4294967296*(a-(a|0))|0},k=2,n=0;64>n;){var j;a:{j=k;for(var u=h.sqrt(j),t=2;t<=u;t++)if(!(j%t)){j=!1;break a}j=!0}j&&(8>n&&(m[n]=l(h.pow(k,0.5))),r[n]=l(h.pow(k,1/3)),n++);k++}var a=[],f=f.SHA256=q.extend({_doReset:function(){this._hash=new g.init(m.slice(0))},_doProcessBlock:function(c,d){for(var b=this._hash.words,e=b[0],f=b[1],g=b[2],j=b[3],h=b[4],m=b[5],n=b[6],q=b[7],p=0;64>p;p++){if(16>p)a[p]=
c[d+p]|0;else{var k=a[p-15],l=a[p-2];a[p]=((k<<25|k>>>7)^(k<<14|k>>>18)^k>>>3)+a[p-7]+((l<<15|l>>>17)^(l<<13|l>>>19)^l>>>10)+a[p-16]}k=q+((h<<26|h>>>6)^(h<<21|h>>>11)^(h<<7|h>>>25))+(h&m^~h&n)+r[p]+a[p];l=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&f^e&g^f&g);q=n;n=m;m=h;h=j+k|0;j=g;g=f;f=e;e=k+l|0}b[0]=b[0]+e|0;b[1]=b[1]+f|0;b[2]=b[2]+g|0;b[3]=b[3]+j|0;b[4]=b[4]+h|0;b[5]=b[5]+m|0;b[6]=b[6]+n|0;b[7]=b[7]+q|0},_doFinalize:function(){var a=this._data,d=a.words,b=8*this._nDataBytes,e=8*a.sigBytes;
d[e>>>5]|=128<<24-e%32;d[(e+64>>>9<<4)+14]=h.floor(b/4294967296);d[(e+64>>>9<<4)+15]=b;a.sigBytes=4*d.length;this._process();return this._hash},clone:function(){var a=q.clone.call(this);a._hash=this._hash.clone();return a}});s.SHA256=q._createHelper(f);s.HmacSHA256=q._createHmacHelper(f)})(Math);
(function(){var h=CryptoJS,s=h.enc.Utf8;h.algo.HMAC=h.lib.Base.extend({init:function(f,g){f=this._hasher=new f.init;"string"==typeof g&&(g=s.parse(g));var h=f.blockSize,m=4*h;g.sigBytes>m&&(g=f.finalize(g));g.clamp();for(var r=this._oKey=g.clone(),l=this._iKey=g.clone(),k=r.words,n=l.words,j=0;j<h;j++)k[j]^=1549556828,n[j]^=909522486;r.sigBytes=l.sigBytes=m;this.reset()},reset:function(){var f=this._hasher;f.reset();f.update(this._iKey)},update:function(f){this._hasher.update(f);return this},finalize:function(f){var g=
this._hasher;f=g.finalize(f);g.reset();return g.finalize(this._oKey.clone().concat(f))}})})();
//oauth-1.0a
if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') {
module.exports = OAuth;
}
/**
* Constructor
* #param {Object} opts consumer key and secret
*/
function OAuth(opts) {
if(!(this instanceof OAuth)) {
return new OAuth(opts);
}
if(!opts) {
opts = {};
}
if(!opts.consumer) {
throw new Error('consumer option is required');
}
this.consumer = opts.consumer;
this.nonce_length = opts.nonce_length || 32;
this.version = opts.version || '1.0';
this.parameter_seperator = opts.parameter_seperator || ', ';
this.realm = opts.realm;
if(typeof opts.last_ampersand === 'undefined') {
this.last_ampersand = true;
} else {
this.last_ampersand = opts.last_ampersand;
}
// default signature_method is 'PLAINTEXT'
this.signature_method = opts.signature_method || 'PLAINTEXT';
if(this.signature_method == 'PLAINTEXT' && !opts.hash_function) {
opts.hash_function = function(base_string, key) {
return key;
}
}
if(!opts.hash_function) {
throw new Error('hash_function option is required');
}
this.hash_function = opts.hash_function;
this.body_hash_function = opts.body_hash_function || this.hash_function;
}
/**
* OAuth request authorize
* #param {Object} request data
* {
* method,
* url,
* data
* }
* #param {Object} key and secret token
* #return {Object} OAuth Authorized data
*/
OAuth.prototype.authorize = function(request, token) {
var oauth_data = {
oauth_consumer_key: this.consumer.key,
oauth_nonce: this.getNonce(),
oauth_signature_method: this.signature_method,
oauth_timestamp: this.getTimeStamp(),
oauth_version: this.version
};
if(!token) {
token = {};
}
if(token.key !== undefined) {
oauth_data.oauth_token = token.key;
}
if(!request.data) {
request.data = {};
}
if(request.includeBodyHash) {
oauth_data.oauth_body_hash = this.getBodyHash(request, token.secret)
}
oauth_data.oauth_signature = this.getSignature(request, token.secret, oauth_data);
return oauth_data;
};
/**
* Create a OAuth Signature
* #param {Object} request data
* #param {Object} token_secret key and secret token
* #param {Object} oauth_data OAuth data
* #return {String} Signature
*/
OAuth.prototype.getSignature = function(request, token_secret, oauth_data) {
return this.hash_function(this.getBaseString(request, oauth_data), this.getSigningKey(token_secret));
};
/**
* Create a OAuth Body Hash
* #param {Object} request data
*/
OAuth.prototype.getBodyHash = function(request, token_secret) {
var body = typeof request.data === 'string' ? request.data : JSON.stringify(request.data)
if (!this.body_hash_function) {
throw new Error('body_hash_function option is required');
}
return this.body_hash_function(body, this.getSigningKey(token_secret))
};
/**
* Base String = Method + Base Url + ParameterString
* #param {Object} request data
* #param {Object} OAuth data
* #return {String} Base String
*/
OAuth.prototype.getBaseString = function(request, oauth_data) {
return request.method.toUpperCase() + '&' + this.percentEncode(this.getBaseUrl(request.url)) + '&' + this.percentEncode(this.getParameterString(request, oauth_data));
};
/**
* Get data from url
* -> merge with oauth data
* -> percent encode key & value
* -> sort
*
* #param {Object} request data
* #param {Object} OAuth data
* #return {Object} Parameter string data
*/
OAuth.prototype.getParameterString = function(request, oauth_data) {
var base_string_data;
if (oauth_data.oauth_body_hash) {
base_string_data = this.sortObject(this.percentEncodeData(this.mergeObject(oauth_data, this.deParamUrl(request.url))));
} else {
base_string_data = this.sortObject(this.percentEncodeData(this.mergeObject(oauth_data, this.mergeObject(request.data, this.deParamUrl(request.url)))));
}
var data_str = '';
//base_string_data to string
for(var i = 0; i < base_string_data.length; i++) {
var key = base_string_data[i].key;
var value = base_string_data[i].value;
// check if the value is an array
// this means that this key has multiple values
if (value && Array.isArray(value)){
// sort the array first
value.sort();
var valString = "";
// serialize all values for this key: e.g. formkey=formvalue1&formkey=formvalue2
value.forEach((function(item, i){
valString += key + '=' + item;
if (i < value.length){
valString += "&";
}
}).bind(this));
data_str += valString;
} else {
data_str += key + '=' + value + '&';
}
}
//remove the last character
data_str = data_str.substr(0, data_str.length - 1);
return data_str;
};
/**
* Create a Signing Key
* #param {String} token_secret Secret Token
* #return {String} Signing Key
*/
OAuth.prototype.getSigningKey = function(token_secret) {
token_secret = token_secret || '';
if(!this.last_ampersand && !token_secret) {
return this.percentEncode(this.consumer.secret);
}
return this.percentEncode(this.consumer.secret) + '&' + this.percentEncode(token_secret);
};
/**
* Get base url
* #param {String} url
* #return {String}
*/
OAuth.prototype.getBaseUrl = function(url) {
return url.split('?')[0];
};
/**
* Get data from String
* #param {String} string
* #return {Object}
*/
OAuth.prototype.deParam = function(string) {
var arr = string.split('&');
var data = {};
for(var i = 0; i < arr.length; i++) {
var item = arr[i].split('=');
// '' value
item[1] = item[1] || '';
// check if the key already exists
// this can occur if the QS part of the url contains duplicate keys like this: ?formkey=formvalue1&formkey=formvalue2
if (data[item[0]]){
// the key exists already
if (!Array.isArray(data[item[0]])) {
// replace the value with an array containing the already present value
data[item[0]] = [data[item[0]]];
}
// and add the new found value to it
data[item[0]].push(decodeURIComponent(item[1]));
} else {
// it doesn't exist, just put the found value in the data object
data[item[0]] = decodeURIComponent(item[1]);
}
}
return data;
};
/**
* Get data from url
* #param {String} url
* #return {Object}
*/
OAuth.prototype.deParamUrl = function(url) {
var tmp = url.split('?');
if (tmp.length === 1)
return {};
return this.deParam(tmp[1]);
};
/**
* Percent Encode
* #param {String} str
* #return {String} percent encoded string
*/
OAuth.prototype.percentEncode = function(str) {
return encodeURIComponent(str)
.replace(/\!/g, "%21")
.replace(/\*/g, "%2A")
.replace(/\'/g, "%27")
.replace(/\(/g, "%28")
.replace(/\)/g, "%29");
};
/**
* Percent Encode Object
* #param {Object} data
* #return {Object} percent encoded data
*/
OAuth.prototype.percentEncodeData = function(data) {
var result = {};
for(var key in data) {
var value = data[key];
// check if the value is an array
if (value && Array.isArray(value)){
var newValue = [];
// percentEncode every value
value.forEach((function(val){
newValue.push(this.percentEncode(val));
}).bind(this));
value = newValue;
} else {
value = this.percentEncode(value);
}
result[this.percentEncode(key)] = value;
}
return result;
};
/**
* Get OAuth data as Header
* #param {Object} oauth_data
* #return {String} Header data key - value
*/
OAuth.prototype.toHeader = function(oauth_data) {
var sorted = this.sortObject(oauth_data);
var header_value = 'OAuth ';
if (this.realm) {
header_value += 'realm="' + this.realm + '"' + this.parameter_seperator;
}
for(var i = 0; i < sorted.length; i++) {
if (sorted[i].key.indexOf('oauth_') !== 0)
continue;
header_value += this.percentEncode(sorted[i].key) + '="' + this.percentEncode(sorted[i].value) + '"' + this.parameter_seperator;
}
return {
Authorization: header_value.substr(0, header_value.length - this.parameter_seperator.length) //cut the last chars
};
};
/**
* Create a random word characters string with input length
* #return {String} a random word characters string
*/
OAuth.prototype.getNonce = function() {
var word_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
var result = '';
for(var i = 0; i < this.nonce_length; i++) {
result += word_characters[parseInt(Math.random() * word_characters.length, 10)];
}
return result;
};
/**
* Get Current Unix TimeStamp
* #return {Int} current unix timestamp
*/
OAuth.prototype.getTimeStamp = function() {
return parseInt(new Date().getTime()/1000, 10);
};
////////////////////// HELPER FUNCTIONS //////////////////////
/**
* Merge object
* #param {Object} obj1
* #param {Object} obj2
* #return {Object}
*/
OAuth.prototype.mergeObject = function(obj1, obj2) {
obj1 = obj1 || {};
obj2 = obj2 || {};
var merged_obj = obj1;
for(var key in obj2) {
merged_obj[key] = obj2[key];
}
return merged_obj;
};
/**
* Sort object by key
* #param {Object} data
* #return {Array} sorted array
*/
OAuth.prototype.sortObject = function(data) {
var keys = Object.keys(data);
var result = [];
keys.sort();
for(var i = 0; i < keys.length; i++) {
var key = keys[i];
result.push({
key: key,
value: data[key],
});
}
return result;
};
//NETSUITE'S RESTLET
function callRESTlet(request, response) {
var remoteAccountID = 'ACCOUNT ID HERE';
var restletUrl = 'https://rest.netsuite.com/app/site/hosting/restlet.nl?script=992&deploy=1';
//user token
var token = {
key: 'ACCESS KEY HERE',
secret: 'ACCESS SECRET HERE'
};
//app credentials
var oauth = OAuth({
consumer: {
key: 'INTEGRATION KEY HERE',
secret: 'INTEGRATION SECRET HERE'
},
signature_method: 'HMAC-SHA1',
hash_function: function(base_string, key)
{
return CryptoJS.HmacSHA1(base_string, key).toString(CryptoJS.enc.Base64);
}
});
var request_data = {
url: restletUrl,
method: 'GET',
data: {}
};
var oauth_data = {
oauth_consumer_key: oauth.consumer.key,
oauth_nonce: oauth.getNonce(),
oauth_signature_method: oauth.signature_method,
oauth_timestamp: oauth.getTimeStamp(),
oauth_version: '1.0',
oauth_token: token.key,
realm: remoteAccountID
};
var headerWithRealm = oauth.toHeader(oauth.authorize(request_data, token));
headerWithRealm.Authorization += ',realm="' + remoteAccountID + '"';
var restResponse = nlapiRequestURL(restletUrl, null, headerWithRealm, null, "GET");
var html = 'Calling: ' +
restletUrl +
'<br><br>' +
'Generated OAuth header:<br>' +
headerWithRealm.Authorization +
'<br><br>' +
'Response:<br>' +
restResponse.getBody()
response.write(html);
}
EDIT: Just published an npm module which should make things easier: https://www.npmjs.com/package/nsrestlet
Was able to get some code working after hunting through GitHub Code commits. Still, bknights response is really good.
Here's what I got working.
Assuming you have Node.js and npm installed, run:
npm install request
npm install oauth-1.0a#1.0.1
It's really important that it's version 1.0.1.
Once you have that, this code should work:
/*
================= REQUIRED USER ACCOUNT INFORMATION ==============================================
*/
var accountID = 'PUT ACCOUNT ID HERE';
var token = {
public: 'PUT TOKEN KEY HERE',
secret: 'PUB TOKEN SECRET HERE'
};
var consumer = {
public: 'PUT CONSUMER KEY HERE',
secret: 'PUT CONSUMER SECRET HERE'
};
//use the full restlet URL, not the rest.netsuite.com URL
//for example, https://YOURACCOUNTNUMBER.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=SCRIPTNUMBER&deploy=DEPLOYNUMBER
var restlet_url = 'PUT YOUR RESTLET URL HERE';
/*
=========================================================================================================
*/
//REQUIRED NPM MODULES
const request = require('request');
const OAuth = require('oauth-1.0a'); //version 1.0.1, don't do version 1.1.0
//SET UP THE OAUTH OBJECT
var oauth = OAuth({
consumer: consumer,
signature_method: 'HMAC-SHA256' //you can also use HMAC-SHA1 but HMAC-SHA256 is more secure (supposedly)
});
//SET UP THE REQUEST OBJECT
var request_data = {
url: restlet_url,
method: 'POST',
};
//GET THE AUTHORIZATION AND STICK IT IN THE HEADER, ALONG WITH THE REALM AND CONTENT-TYPE
var authorization = oauth.authorize(request_data, token);
var header = oauth.toHeader(authorization);
header.Authorization += ', realm="' + accountID + '"';
header['content-type'] = 'application/json';
//MAKE THE REQUEST
request({
url: request_data.url,
method: request_data.method,
headers: header,
json: {
message: "test123" //this is your payload
}
}, function(error, response, body) {
if(error)
{
console.log(error);
}
else
{
console.log(body);
}
});
If anybody has any problems with this code, leave a response and I'll do my best to help.
Netsuite's node samples use oauth-1.0a
https://netsuite.custhelp.com/app/answers/detail/a_id/42171
and their sample from https://netsuite.custhelp.com/app/answers/detail/a_id/42172/
is what I've had in production for a couple of years and works well.
var Promise = require('bluebird');
var request = require('request');
var crypto = require('crypto');
var OAuth = require('oauth-1.0a');
var Agent = require('https').Agent;
//var debug = require('debug')('kotn-ns');
function promiseTry(pSrc, maxTries, minDelay, maxDelay, canRetry){ //NS prone to spurious failures due to overloading
return new Promise(function(resolve, reject){
minDelay = minDelay || 0;
var delaySize = maxDelay - minDelay;
var t = function(){ return Math.floor(Math.random()* delaySize)+ minDelay;};
var firstReason = null;
function doRetry(triesLeft){
pSrc().then(function(data){
resolve(data);
}).catch(function(reason){
if(!firstReason) firstReason = reason;
console.error('in retry error with '+reason.toString());
if(triesLeft && canRetry(reason)) setTimeout(function(){ doRetry(triesLeft-1);}, t());
else reject(firstReason);
});
}
doRetry(maxTries -1);
});
}
function hasReason(msg, reasons){
for(var i = 0; i< reasons.length;i++){
if(msg.indexOf(reasons[i]) != -1) return true;
}
return false;
}
var agentPool = {};
function getAgent(accountId, tokenId){
var agentKey = accountId+'::'+ tokenId;
var agent = agentPool[agentKey];
if(!agent){
console.log('new agent for '+agentKey)
agent = new Agent({
keepAlive:false,
maxSockets:5
});
agentPool[agentKey] = agent;
}
return agent;
}
/**
* [RESTHandler description]
* #param {options} options {accountId, consumerKey,consumerSecret,tokenId,tokenSecret}
*/
function RESTHandler(options) {
var config = Object.assign({
maxTries:3,
minRetryDelay: 800,
maxRetryDelay:30000,
canRetry: function(reason){
var reasonText = reason.message || JSON.stringify(reason);
if(hasReason(reasonText, ['ECONNRESET', 'ESOCKETTIMEDOUT','ETIMEDOUT', 'SSS_REQUEST_LIMIT_EXCEEDED'])) {
console.error('retrying because: '+reasonText);
return true;
}
console.error('no retry with: '+reasonText);
return false;
}
}, options);
var oauth = OAuth({
consumer: {
key: config.consumerKey,
secret: config.consumerSecret
},
signature_method: 'HMAC-SHA1',
parameter_seperator: ',',
hash_function: function(base_string, key) {
return crypto.createHmac('sha1', key).update(base_string).digest('base64');
}
});
var token = {
key: config.tokenId,
secret: config.tokenSecret
};
function makeRequest(url, method, payload) {
var requestData = {
url: url,
method: method
};
if(payload){
requestData.body = payload;
}
var headers = oauth.toHeader(oauth.authorize(requestData, token));
headers.Authorization += ',realm="' + config.accountId + '"';
headers.authorization = headers.Authorization;
delete headers.Authorization;
headers['content-type'] = 'application/json';
headers['accept'] = 'application/json';
//console.log(JSON.stringify(headers, null, ' '));
requestData.headers = headers;
Object.assign(requestData, {
pool:getAgent(config.accountId, config.tokenId),
timeout : 30000,
strictSSL : true
});
// requestData.json = true;
// return new Promise(function(resolve){
// resolve({'headers' : 'done'});
// });
var processRequest = function(){
return new Promise(function(resolve, reject) {
request(requestData, function(error, response, body) {
if(error){
console.error('error calling: '+ requestData.url);
console.error(error);
reject((error instanceof Error) ? error : new Error(JSON.stringify(error)));
return;
}
if(!body || !(/"success"/).test(body)) {
console.log(method +' '+ response.statusCode +' '+ url +'\n\t'+body);
reject(new Error(body || 'unexpected error'));
return;
}
try{
resolve(JSON.parse(body));
}catch(e){
console.trace(e);
reject(e);
}
});
});
};
return promiseTry(processRequest, config.maxTries, config.maxRetryDelay, config.minRetryDelay, config.canRetry);
}
return{
get: function(url){
return makeRequest(url, 'GET');
},
put: function(url, data){
return makeRequest(url, 'PUT', data);
},
post: function(url, data){
return makeRequest(url, 'POST', data);
},
destroy : function(){
//nsAgent.destroy();
}
};
}
module.exports = RESTHandler;
More up-to-date as of 2022-12-12
replaced request with its successor needle and removed the now unnecessary bluebird
const needle = require('needle');
const crypto = require('crypto');
const OAuth = require('oauth-1.0a');
const Agent = require('https').Agent;
const debug = require('debug')('kotn-nso');
function promiseTry(pSrc, maxTries, minDelay, maxDelay, canRetry){ //NS prone to spurious failures due to overloading
return new Promise((resolve, reject)=>{
minDelay = minDelay || 0;
const delaySize = maxDelay - minDelay;
const t = function(){ return Math.floor(Math.random()* delaySize)+ minDelay;};
let firstReason = null;
function doRetry(triesLeft){
pSrc().then((data)=>{
resolve(data);
}).catch((reason)=>{
if(!firstReason) firstReason = reason;
console.error('in retry error with '+ triesLeft +' for '+reason.toString());
if(triesLeft && canRetry(reason)){
setTimeout(()=>{ doRetry(triesLeft-1);}, t());
}
else reject(firstReason);
});
}
doRetry(maxTries -1);
});
}
function hasReason(msg, reasons){
for(var i = 0; i< reasons.length;i++){
if(msg.indexOf(reasons[i]) != -1) return true;
}
return false;
}
var agentPool = {};
function getAgent(accountId, maxSockets){
var agentKey = accountId+'::'; // + tokenId;
var agent = agentPool[agentKey];
if(!agent){
console.log('new agent for '+agentKey);
agent = new Agent({
keepAlive:false,
maxSockets:maxSockets || 2 // one in reserve for slow closers
});
agentPool[agentKey] = agent;
}
return agent;
}
/**
* [RESTHandler description]
* #param {options} options {accountId, consumerKey,consumerSecret,tokenId,tokenSecret,maxSockets}
*/
function RESTHandler(options) {
const config = Object.assign({
maxTries:3,
minRetryDelay: 400,
maxRetryDelay:30000,
canRetry: function(reason){
var reasonText = reason.message || JSON.stringify(reason);
if(hasReason(reasonText, ['ECONNRESET', 'ESOCKETTIMEDOUT','ETIMEDOUT', 'SSS_REQUEST_LIMIT_EXCEEDED'])) {
console.error('retrying because: '+reasonText);
return true;
}
console.error('no retry with: '+reasonText);
return false;
}
}, options);
const oauth = OAuth({
consumer: {
key: config.consumerKey,
secret: config.consumerSecret
},
signature_method: 'HMAC-SHA256',
parameter_seperator: ',',
hash_function: function(base_string, key) {
return crypto.createHmac('sha256', key).update(base_string).digest('base64');
}
});
const token = {
key: config.tokenId,
secret: config.tokenSecret
};
function makeRequest(url, method, payload) {
debug(method +' '+ JSON.stringify(url));
var requestData = {
url: url,
method: method
};
if(payload){
requestData.body = payload;
}
var headers = oauth.toHeader(oauth.authorize(requestData, token));
headers.Authorization += ',realm="' + config.accountId + '"';
headers.authorization = headers.Authorization;
delete headers.Authorization;
headers['content-type'] = 'application/json';
headers['accept'] = 'application/json';
//console.log(JSON.stringify(headers, null, ' '));
const options = {
headers:headers,
agent:getAgent(config.accountId, config.maxSockets),
timeout : 30000,
strictSSL : true,
time:false
};
var processRequest = function(){
var headers = null;
return needle(method.toLowerCase(), url, payload, options).then(resp=>{
debug(resp.statusCode +' ' + JSON.stringify(resp.headers, null, ' '));
headers = resp.headers;
if(resp.statusCode != 200 && resp.statusCode != 201){
throw new Error(resp.statusCode +': '+ (resp.body || 'unexpected error'));
}
if(!resp.body) throw new Error('Unexpected Response');
return resp.body;
}).catch(error=>{
if(headers){
debug('Error returned with ' + JSON.stringify(headers));
}
const msg = error instanceof Error ? error.message : JSON.stringify(error);
console.error(method +' error on '+ url + ', '+ msg);
throw (error instanceof Error) ? error : new Error(msg);
});
};
return promiseTry(processRequest, config.maxTries, config.maxRetryDelay, config.minRetryDelay, config.canRetry);
}
return{
get: function(url){
return makeRequest(url, 'GET');
},
put: function(url, data){
return makeRequest(url, 'PUT', data);
},
post: function(url, data){
return makeRequest(url, 'POST', data);
},
destroy : function(){
//nsAgent.destroy();
}
};
}
module.exports = RESTHandler;
Related
Is it possible to get Google Ouath2 access token without setting a redirect URI?
I am trying to implement Google Oauth2 consent screen within a popup but it says redirect URI mismatch. Is there any way where I can set up a web Ouath Client App without setting redirect uri in the dashboard? I know setting up client type from web to others or application may solve this issue. But I want to implement it for web type only. Is this possible? <!DOCTYPE html> <html> <head> <script> 'use strict'; var GO2 = function GO2(options) { if (!options || !options.clientId) { throw 'You need to at least set the clientId'; } if (typeof window != 'undefined'){ this._redirectUri = window.location.href.substr(0, window.location.href.length - window.location.hash.length) .replace(/#$/, ''); } // Save the client id this._clientId = options.clientId; // if scope is an array, convert it into a string. if (options.scope) { this._scope = Array.isArray(options.scope) ? options.scope.join(' ') : options.scope; } // rewrite redirect_uri if (options.redirectUri) { this._redirectUri = options.redirectUri; } // popup dimensions if (options.popupHeight) { this._popupHeight = options.popupHeight; } if (options.popupWidth) { this._popupWidth = options.popupWidth; } if (options.responseType) { this._responseType = options.responseType; } if (options.accessType) { this._accessType = options.accessType; } }; GO2.receiveMessage = function GO2_receiveMessage() { var go2; if (window.opener && window.opener.__windowPendingGO2) { go2 = window.opener.__windowPendingGO2; } if (window.parent && window.parent.__windowPendingGO2) { go2 = window.parent.__windowPendingGO2; } var hash = window.location.hash; if (go2 && hash.indexOf('access_token') !== -1) { go2._handleMessage( hash.replace(/^.*access_token=([^&]+).*$/, '$1'), parseInt(hash.replace(/^.*expires_in=([^&]+).*$/, '$1'), 10), hash.replace(/^.*state=go2_([^&]+).*$/, '$1') ); } if (go2 && window.location.search.indexOf('code=')) { go2._handleMessage( window.location.search.replace(/^.*code=([^&]+).*$/, '$1'), null, window.location.search.replace(/^.*state=go2_([^&]+).*$/, '$1') ); } if (go2 && window.location.search.indexOf('error=')) { go2._handleMessage(false); } }; GO2.prototype = { WINDOW_NAME: 'google_oauth2_login_popup', OAUTH_URL: 'https://accounts.google.com/o/oauth2/v2/auth', _clientId: undefined, _scope: 'https://www.googleapis.com/auth/plus.me', _redirectUri: '', _popupWindow: null, _immediateFrame: null, _stateId: Math.random().toString(32).substr(2), _accessToken: undefined, _timer: undefined, _popupWidth: 500, _popupHeight: 400, _responseType: 'token', _accessType: 'online', onlogin: null, onlogout: null, login: function go2_login(forceApprovalPrompt, immediate) { if (this._accessToken) { return; } this._removePendingWindows(); window.__windowPendingGO2 = this; var url = this.OAUTH_URL + '?response_type=' + this._responseType + '&access_type='+ encodeURIComponent(this._accessType) + '&redirect_uri=' + encodeURIComponent(this._redirectUri) + '&scope=' + encodeURIComponent(this._scope) + '&state=go2_' + this._stateId + '&client_id=' + encodeURIComponent(this._clientId); console.log(url); if (!immediate && forceApprovalPrompt) { url += '&approval_prompt=force'; } if (immediate) { url += '&approval_prompt=auto'; // Open up an iframe to login // We might not be able to hear any of the callback // because of X-Frame-Options. var immediateFrame = this._immediateFrame = document.createElement('iframe'); immediateFrame.src = url; immediateFrame.hidden = true; immediateFrame.width = immediateFrame.height = 1; immediateFrame.name = this.WINDOW_NAME; document.body.appendChild(immediateFrame); return; } // Open the popup var left = window.screenX + (window.outerWidth / 2) - (this._popupWidth / 2); var top = window.screenY + (window.outerHeight / 2) - (this._popupHeight / 2); var windowFeatures = 'width=' + this._popupWidth + ',height=' + this._popupHeight + ',top=' + top + ',left=' + left + ',location=no,toolbar=no,menubar=no'; this._popupWindow = window.open(url, this.WINDOW_NAME, windowFeatures); }, logout: function go2_logout() { if (!this._accessToken) { return; } this._removePendingWindows(); clearTimeout(this._timer); this._accessToken = undefined; if (this.onlogout) { this.onlogout(); } }, getAccessToken: function go2_getAccessToken() { return this._accessToken; }, // receive token from popup / frame _handleMessage: function go2_handleMessage(token, expiresIn, stateId) { if (this._stateId !== stateId) { return; } this._removePendingWindows(); // Do nothing if there is no token received. if (!token) { return; } this._accessToken = token; if (this.onlogin) { this.onlogin(this._accessToken); } if (expiresIn) { // Remove the token if timed out. clearTimeout(this._timer); this._timer = setTimeout( function tokenTimeout() { this._accessToken = undefined; if (this.onlogout) { this.onlogout(); } }.bind(this), expiresIn * 1000 ); } }, destory: function go2_destory() { if (this._timer) { clearTimeout(this._timer); } this._removePendingWindows(); }, _removePendingWindows: function go2_removePendingWindows() { if (this._immediateFrame) { document.body.removeChild(this._immediateFrame); this._immediateFrame = null; } if (this._popupWindow) { this._popupWindow.close(); this._popupWindow = null; } if (window.__windowPendingGO2 === this) { delete window.__windowPendingGO2; } } }; // if the context is the browser if (typeof window !== 'undefined') { // If the script loads in a popup matches the WINDOW_NAME, // we need to handle the request instead. if (window.name === GO2.prototype.WINDOW_NAME) { GO2.receiveMessage(); } } // Expose the library as an AMD module if (typeof define === 'function' && define.amd) { define('google-oauth2-web-client', [], function () { return GO2; }); } else if (typeof module === 'object' && typeof require === 'function') { // export GO2 in Node.js, assuming we are being browserify'd. module.exports = GO2; if (require.main === module) { console.error('Error: GO2 is not meant to be executed directly.'); } } else { window.GO2 = GO2; } function test(){ var go2 = new GO2({ clientId: 'dfsdffdfgsfsdfggdgd.apps.googleusercontent.com', redirectUri: 'http://localhost:8888/gapi/test.html', responseType: 'code', accessType: 'offline' }); go2.login(); } </script> </head> <body> <a href='#' onClick='test();'> Click here to login </a> </body> </html>
It looks like you're using the implicit grant type which requires a redirect uri with response_type=token. Can you use the authorization code grant type? The redirect uri is optional for the authorization code grant type. https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1
Not able to use the updated value -- Flutter
I'm updating the totalPayable value in else if, but I'm not able to use the updated value anywhere in the code when I call getOrder(). Is it an API problem or what can anyone help me with the code? else if (isOrderInitiated == false){ getCleintOrderFromApi(); debugPrint("ifelse" + totalPayable.toString()); } getClientOrderFromApi() { orders.clear(); totalPayable = 0.0; api.getCleintOrder().then((list) { list.forEach((order) { if(order.is_placed) { order.status = ORDER_STATUS[0]; } else if(!order.is_placed) { order.status = ORDER_STATUS[2]; } debugPrint("ORDER_STATUS from remote" + order.status); for (var j = 0; j < order.items.length; j++) { FoodItemOrder item = order.items[j]; totalPayable = totalPayable + item.unitPrice * item.quantity; debugPrint(" total payable in order "+ totalPayable.toString()); } orders.add(order); debugPrint("itemsin order"+orders.last.items.length.toString()); }); currentOrderList.clear(); currentOrderList.addAll(orders); orderItemsSink.add(orders); }); } } The debugPrint in getClientOrderFromApi() is showing the updated result, but in else if debugPrint(" ifelse "+ totalPayable.toString()); it is not showing the updated value which is why wherever I use totalPayable it is not showing the desired value.
Future<List<Order>> getCleintOrder() async { MakeOrder clientOrderRequest = MakeOrder(); //currentCafe; clientOrderRequest.caffeID = currentCafe.caffeId; clientOrderRequest.tableidtimestamp = currentUser.tableIdTimestamp; // offset = 160; String url = BASE_URL + BASE_URL_GET_CLIENT_ORDER; debugPrint("requesting getCleintOrder --- \n" + url + "\n " + clientOrderRequest.toClietnOrderJson().toString()); var response = await http .post( url, headers: { HttpHeaders.contentTypeHeader: 'application/json', // HttpHeaders.authorizationHeader : '' }, body: json.encode(clientOrderRequest.toClietnOrderJson()), ) .catchError( (error) { ////debugPrint(error.toString()); return false; }, ); var jsonObj = json.decode(response.body); ////debugPrint(jsonObj.toString()); List<Order> orders = []; try { jsonObj.forEach((newJson) { List<Order> orderList = (newJson["orders"] as List) .map((neworderJson) => Order.fromJSON(neworderJson)) .toList().cast<Order>(); orders.addAll(orderList); }); } catch (e) { ////debugPrint(e.toString()); } // debugPrint("total client orders " + orders.length.toString()); return orders; } This is my api call for refernece.
In NetSuite with SuiteScript 2.0 unable to send a file with HTTP POST request with a content-type multipart/form-data
I am not able to send my "multipart/form-data' file to this API. If I use POSTMAN it's working but with the https post method it seems that netsuite doesn't recognize the "form-data" content-type. Somebody knows how to send a form-data with SuiteScript 2 ? Here is a part of my code: var fileObj = file.create({ name: invoiceNumber + '_ubl.xml', fileType: file.Type.XMLDOC, contents: einvoicecontentwithpdf, folder : 120, isOnline : false }); var headers = { 'Authorization': 'Basic xxxxxxxxxxxxxxxxxxxxx', 'Content-Type': 'multipart/form-data' }; var response = https.post({ url: 'https://community-api-uat-1-2.nxt.uat.unifiedpost.com/api/universal_connector/v1/uc/ar', body: { 'file': fileObj }, headers: headers });
You have to build the whole body yourself. This works as much as I've tested so far. Code may look a little non-idomatic because it's compiled from Typescript. Note that to include non-text files this would have to be adapted to base64 encode the file bodies. /** * multiPartUpload.js * #NApiVersion 2.x */ define(["require", "exports", "N/https", "N/file", "N/log"], function (require, exports, http, file, log) { Object.defineProperty(exports, "__esModule", { value: true }); var types = {}; types[file.Type.AUTOCAD] = 'application/x-autocad'; types[file.Type.BMPIMAGE] = 'image/x-xbitmap'; types[file.Type.CSV] = 'text/csv'; types[file.Type.EXCEL] = 'application/vnd.ms-excel'; types[file.Type.FLASH] = 'application/x-shockwave-flash'; types[file.Type.GIFIMAGE] = 'image/gif'; types[file.Type.GZIP] = 'application/?x-?gzip-?compressed'; types[file.Type.HTMLDOC] = 'text/html'; types[file.Type.ICON] = 'image/ico'; types[file.Type.JAVASCRIPT] = 'text/javascript'; types[file.Type.JPGIMAGE] = 'image/jpeg'; types[file.Type.JSON] = 'application/json'; types[file.Type.MESSAGERFC] = 'message/rfc822'; types[file.Type.MP3] = 'audio/mpeg'; types[file.Type.MPEGMOVIE] = 'video/mpeg'; types[file.Type.MSPROJECT] = 'application/vnd.ms-project'; types[file.Type.PDF] = 'application/pdf'; types[file.Type.PJPGIMAGE] = 'image/pjpeg'; types[file.Type.PLAINTEXT] = 'text/plain'; types[file.Type.PNGIMAGE] = 'image/x-png'; types[file.Type.POSTSCRIPT] = 'application/postscript'; types[file.Type.POWERPOINT] = 'application/?vnd.?ms-?powerpoint'; types[file.Type.QUICKTIME] = 'video/quicktime'; types[file.Type.RTF] = 'application/rtf'; types[file.Type.SMS] = 'application/sms'; types[file.Type.STYLESHEET] = 'text/css'; types[file.Type.TIFFIMAGE] = 'image/tiff'; types[file.Type.VISIO] = 'application/vnd.visio'; types[file.Type.WORD] = 'application/msword'; types[file.Type.XMLDOC] = 'text/xml'; types[file.Type.ZIP] = 'application/zip'; function getContentType(f) { var mime = types[f.fileType]; var charset = f.encoding; var ct = 'Content-Type: ' + mime + (charset ? ';charset=' + charset : ''); log.debug({ title: 'content for ' + f.name, details: ct }); return ct; } function isFile(o) { return (typeof o == 'object' && typeof o.fileType != 'undefined'); } /** * Creates a multipart upload * #param {string} url to post to * #param {object} headers key/value of headers; include Auth headers if needed * #param {array} parts array of {name:string, value:file|string} */ function uploadParts(url, headers, parts) { var boundary = 'someuniqueboundaryasciistring'; headers['content-type'] = 'multipart/form-data; boundary=' + boundary; // Body var body = []; parts.forEach(function (p, idx) { var partIsFile = isFile(p.value); body.push('--' + boundary); body.push('Content-Disposition: form-data; name="' + p.name + '"' + (partIsFile ? ('; filename="' + p.value.name + '"') : '')); if (partIsFile) { var ct = getContentType(p.value); body.push(getContentType(p.value)); if(partIsBinary(ct)){ body.push('Content-Transfer-Encoding: base64'); } } body.push(''); body.push(partIsFile ? p.value.getContents() : p.value); if (idx == parts.length - 1) { body.push('--' + boundary + '--'); body.push(''); } }); // Submit Request try { var response = http.post({ url: url, headers: headers, body: body.join('\r\n') }); return response; } catch (e) { log.error({ title: 'Failed to submit file', details: (e.message || e.toString()) + (e.getStackTrace ? (' \n \n' + e.getStackTrace().join(' \n')) : '') }); } } exports.uploadParts = uploadParts; ; }); a simple test: /** *#NApiVersion 2.x *#NScriptType Suitelet */ define(["require", "exports", "N/file", "./multiPartUpload"], function (require, exports, file, multiPartUpload_1) { Object.defineProperty(exports, "__esModule", { value: true }); function onRequest(context) { var files = [ { name: 'f1', value: file.load({ id: 1056 }) }, // file cabinet ids; you can use dynamic files { name:'t1', value:'test'}, { name: 'f2', value: file.load({ id: 7479 }) } ]; var resp = multiPartUpload_1.uploadParts('https://your-test-server/', {}, files); context.response.write({ output: resp.body }); } exports.onRequest = onRequest; });
How to set the templateUrl in a component in Angular2?
How can I set the templateUrl in code? E.g., if I have #Component({ selector: 'search-load', templateUrl: '/loads/search' }) I want: #Component({ selector: 'search-load', templateUrl: this.language+ 'loads/search' }) where templateUrl is a mvc path. Thank you.
You cannot this in component declaration like this since its outside of component's scope but this is how I do something like this In my component: #Component({ selector: 'live-auction-stats', templateUrl: BaseConfigurations.baseTemplatePath + '/auction-stats.html', }) And In my BaseConfigurations.ts file, I have export abstract class BaseConfigurations { public baseTemplatePath: string = location.origin + '/app/templates'; //you can configure here .... //other base configurations.. .... }
After a long searching i found that node_modules\#angular\platform-browser-dynamic\bundles\platform-browser-dynamic.umd.js is the responsible for loading template by url so i can add some params to url dynamically like this : var lang = JSON.parse(localStorage.getItem("Accept-Language")); xhr.open('GET', lang+url, true); then the final file will be : (function(System, SystemJS) {/** * #license Angular v2.2.3 * (c) 2010-2016 Google, Inc. https://angular.io/ * License: MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('#angular/compiler'), require('#angular/core'), require('#angular/platform-browser')) : typeof define === 'function' && define.amd ? define(['exports', '#angular/compiler', '#angular/core', '#angular/platform-browser'], factory) : (factory((global.ng = global.ng || {}, global.ng.platformBrowserDynamic = global.ng.platformBrowserDynamic || {}),global.ng.compiler,global.ng.core,global.ng.platformBrowser)); }(this, function (exports,_angular_compiler,_angular_core,_angular_platformBrowser) { 'use strict'; var INTERNAL_BROWSER_PLATFORM_PROVIDERS = _angular_platformBrowser.__platform_browser_private__.INTERNAL_BROWSER_PLATFORM_PROVIDERS; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var ResourceLoaderImpl = (function (_super) { __extends(ResourceLoaderImpl, _super); function ResourceLoaderImpl() { _super.apply(this, arguments); } ResourceLoaderImpl.prototype.get = function (url) { var resolve; var reject; var promise = new Promise(function (res, rej) { resolve = res; reject = rej; }); var xhr = new XMLHttpRequest(); var lang = JSON.parse(localStorage.getItem("Accept-Language")); xhr.open('GET', lang+url, true); xhr.responseType = 'text'; xhr.onload = function () { // responseText is the old-school way of retrieving response (supported by IE8 & 9) // response/responseType properties were introduced in ResourceLoader Level2 spec (supported // by IE10) var response = xhr.response || xhr.responseText; // normalize IE9 bug (http://bugs.jquery.com/ticket/1450) var status = xhr.status === 1223 ? 204 : xhr.status; // fix status code when it is 0 (0 status is undocumented). // Occurs when accessing file resources or on Android 4.1 stock browser // while retrieving files from application cache. if (status === 0) { status = response ? 200 : 0; } if (200 <= status && status <= 300) { resolve(response); } else { reject("Failed to load " + url); } }; xhr.onerror = function () { reject("Failed to load " + url); }; xhr.send(); return promise; }; ResourceLoaderImpl.decorators = [ { type: _angular_core.Injectable }, ]; /** #nocollapse */ ResourceLoaderImpl.ctorParameters = []; return ResourceLoaderImpl; }(_angular_compiler.ResourceLoader)); var INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS = [ INTERNAL_BROWSER_PLATFORM_PROVIDERS, { provide: _angular_core.COMPILER_OPTIONS, useValue: { providers: [{ provide: _angular_compiler.ResourceLoader, useClass: ResourceLoaderImpl }] }, multi: true }, ]; /** * #license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ var globalScope; if (typeof window === 'undefined') { if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) { // TODO: Replace any with WorkerGlobalScope from lib.webworker.d.ts #3492 globalScope = self; } else { globalScope = global; } } else { globalScope = window; } // Need to declare a new variable for global here since TypeScript // exports the original value of the symbol. var _global = globalScope; // TODO: remove calls to assert in production environment // Note: Can't just export this and import in in other files // as `assert` is a reserved keyword in Dart _global.assert = function assert(condition) { // TODO: to be fixed properly via #2830, noop for now }; /** * #license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ var __extends$1 = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; /** * An implementation of ResourceLoader that uses a template cache to avoid doing an actual * ResourceLoader. * * The template cache needs to be built and loaded into window.$templateCache * via a separate mechanism. */ var CachedResourceLoader = (function (_super) { __extends$1(CachedResourceLoader, _super); function CachedResourceLoader() { _super.call(this); this._cache = _global.$templateCache; if (this._cache == null) { throw new Error('CachedResourceLoader: Template cache was not found in $templateCache.'); } } CachedResourceLoader.prototype.get = function (url) { if (this._cache.hasOwnProperty(url)) { return Promise.resolve(this._cache[url]); } else { return Promise.reject('CachedResourceLoader: Did not find cached template for ' + url); } }; return CachedResourceLoader; }(_angular_compiler.ResourceLoader)); var __platform_browser_dynamic_private__ = { INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS: INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, ResourceLoaderImpl: ResourceLoaderImpl }; /** * #experimental */ var RESOURCE_CACHE_PROVIDER = [{ provide: _angular_compiler.ResourceLoader, useClass: CachedResourceLoader }]; /** * #stable */ var platformBrowserDynamic = _angular_core.createPlatformFactory(_angular_compiler.platformCoreDynamic, 'browserDynamic', INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS); exports.RESOURCE_CACHE_PROVIDER = RESOURCE_CACHE_PROVIDER; exports.platformBrowserDynamic = platformBrowserDynamic; exports.__platform_browser_dynamic_private__ = __platform_browser_dynamic_private__; })); })(System, System);
Getting Invalid Signature error with woocommerce rest api using oauth 1.0a
I am getting an invalid signature error in woocommerce rest api. I am also using the oauth 1.0a script from ddo https://github.com/ddo/oauth-1.0a. I generated the api keys twice. Also removed the version parameter inside de oauth script like requested on the woocommerce rest api documentation http://woothemes.github.io/woocommerce-rest-api-docs/ url test.dev/wc-api/v3/orders/line_items?oauth_consumer_key=ck_858f9cf8cda8085d5677b2b1d4c12d10897e9702&oauth_nonce=MyriSapnWSopIusSjjuqJ8PLi6RWr0L9&oauth_signature=VfgINTX1FWYu551%2FxlLfipFnDQ8%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1443481966 error {"errors":[{"code":"woocommerce_api_authentication_error","message":"Invalid Signature - provided signature does not match"}]} js var oauth = OAuth({ consumer: { public: 'ck_858f9cf8cda8085d5677b2b1d4c12d10897e9702', secret: 'cs_7f429ec99905bb444e290bd4852a0c0da2545b21 ' }, signature_method: 'HMAC-SHA1' }); var request_data = { url: 'http://test.dev/wc-api/v3/orders/line_items', method: 'GET', } $http({ url: request_data.url, method: request_data.get, params: oauth.authorize(request_data) }).then(function successCallback(response) { console.log(response); }, function errorCallback(response) { console.log(response); });;
I just noticed that your $http method is getting the value of request_data.get instead of request_data.method. I'm sure that's what you were overlooking lol
Fixed it by using a service from Abdul Ahmad: httpService.js angular.module('httpService', []).factory('httpService', httpService); httpService.$inject = ['$http', '$q']; function httpService($http, $q) { var methods = { httpGet : 'GET', httpPost : 'POST', httpPut : 'PUT', httpDelete : 'DELETE' }; function baseGet(url) { return $http.get(url).then( function (result) { return result.data; }, function (result) { return $q.reject(result); } ); } function httpWithParams(url, method, params, data) { return $http({ url: url, method: method, params: params, data: data, dataType: "json", headers: { "Content-Type": "application/json" } }).then( function (result) { return result.data; }, function (result) { return $q.reject(result); } ); } function handleError(error) { console.log(error); } return { baseGet: baseGet, httpWithParams: httpWithParams, handleError: handleError, methods: methods } } And then used this: var oauth = OAuth({ consumer: { public: 'ck_000', secret: 'cs_000' }, signature_method: 'HMAC-SHA1' }); function getMyData() { var request_data = { url: 'http://test.dev/wc-api/v3/products', method: 'get', } return returnData = httpService.httpWithParams(request_data.url, request_data.method, oauth.authorize(request_data)) .then(function(data) { return data; }, function(data) { httpService.handleError(data); return data; }); } Made some modification in the oauth file: if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') { module.exports = OAuth; var CryptoJS = require("crypto-js"); } /** * Constructor * #param {Object} opts consumer key and secret */ function OAuth(opts) { if(!(this instanceof OAuth)) { return new OAuth(opts); } if(!opts) { opts = {}; } if(!opts.consumer) { throw new Error('consumer option is required'); } this.consumer = opts.consumer; this.signature_method = opts.signature_method || 'HMAC-SHA1'; this.nonce_length = opts.nonce_length || 32; //this.version = opts.version || '1.0'; this.parameter_seperator = opts.parameter_seperator || ', '; if(typeof opts.last_ampersand === 'undefined') { this.last_ampersand = true; } else { this.last_ampersand = opts.last_ampersand; } switch (this.signature_method) { case 'HMAC-SHA1': this.hash = function(base_string, key) { return CryptoJS.HmacSHA1(base_string, key).toString(CryptoJS.enc.Base64); }; break; case 'HMAC-SHA256': this.hash = function(base_string, key) { return CryptoJS.HmacSHA256(base_string, key).toString(CryptoJS.enc.Base64); }; break; case 'PLAINTEXT': this.hash = function(base_string, key) { return key; }; break; case 'RSA-SHA1': throw new Error('oauth-1.0a does not support this signature method right now. Coming Soon...'); default: throw new Error('The OAuth 1.0a protocol defines three signature methods: HMAC-SHA1, RSA-SHA1, and PLAINTEXT only'); } } /** * OAuth request authorize * #param {Object} request data * { * method, * url, * data * } * #param {Object} public and secret token * #return {Object} OAuth Authorized data */ OAuth.prototype.authorize = function(request, token) { var oauth_data = { oauth_consumer_key: this.consumer.public, oauth_timestamp: this.getTimeStamp(), oauth_nonce: this.getNonce(), oauth_signature_method: this.signature_method //oauth_version: this.version }; if(!token) { token = {}; } if(token.public) { oauth_data.oauth_token = token.public; } if(!request.data) { request.data = {}; } oauth_data.oauth_signature = this.getSignature(request, token.secret, oauth_data); return oauth_data; }; /** * Create a OAuth Signature * #param {Object} request data * #param {Object} token_secret public and secret token * #param {Object} oauth_data OAuth data * #return {String} Signature */ OAuth.prototype.getSignature = function(request, token_secret, oauth_data) { return this.hash(this.getBaseString(request, oauth_data), this.getSigningKey(token_secret)); }; /** * Base String = Method + Base Url + ParameterString * #param {Object} request data * #param {Object} OAuth data * #return {String} Base String */ OAuth.prototype.getBaseString = function(request, oauth_data) { return request.method.toUpperCase() + '&' + this.percentEncode(this.getBaseUrl(request.url)) + '&' + this.percentEncode(this.getParameterString(request, oauth_data)); }; /** * Get data from url * -> merge with oauth data * -> percent encode key & value * -> sort * * #param {Object} request data * #param {Object} OAuth data * #return {Object} Parameter string data */ OAuth.prototype.getParameterString = function(request, oauth_data) { var base_string_data = this.sortObject(this.percentEncodeData(this.mergeObject(oauth_data, this.mergeObject(request.data, this.deParamUrl(request.url))))); var data_str = ''; //base_string_data to string for(var key in base_string_data) { data_str += key + '=' + base_string_data[key] + '&'; } //remove the last character data_str = data_str.substr(0, data_str.length - 1); return data_str; }; /** * Create a Signing Key * #param {String} token_secret Secret Token * #return {String} Signing Key */ OAuth.prototype.getSigningKey = function(token_secret) { token_secret = token_secret || ''; if(!this.last_ampersand && !token_secret) { return this.percentEncode(this.consumer.secret); } return this.percentEncode(this.consumer.secret) + '&' + this.percentEncode(token_secret); }; /** * Get base url * #param {String} url * #return {String} */ OAuth.prototype.getBaseUrl = function(url) { return url.split('?')[0]; }; /** * Get data from String * #param {String} string * #return {Object} */ OAuth.prototype.deParam = function(string) { var arr = string.split('&'); var data = {}; for(var i = 0; i < arr.length; i++) { var item = arr[i].split('='); data[item[0]] = decodeURIComponent(item[1]); } return data; }; /** * Get data from url * #param {String} url * #return {Object} */ OAuth.prototype.deParamUrl = function(url) { var tmp = url.split('?'); if (tmp.length === 1) return {}; return this.deParam(tmp[1]); }; /** * Percent Encode * #param {String} str * #return {String} percent encoded string */ OAuth.prototype.percentEncode = function(str) { return encodeURIComponent(str) .replace(/\!/g, "%21") .replace(/\*/g, "%2A") .replace(/\'/g, "%27") .replace(/\(/g, "%28") .replace(/\)/g, "%29"); }; /** * Percent Encode Object * #param {Object} data * #return {Object} percent encoded data */ OAuth.prototype.percentEncodeData = function(data) { var result = {}; for(var key in data) { result[this.percentEncode(key)] = this.percentEncode(data[key]); } return result; }; /** * Get OAuth data as Header * #param {Object} oauth_data * #return {String} Header data key - value */ OAuth.prototype.toHeader = function(oauth_data) { oauth_data = this.sortObject(oauth_data); var header_value = 'OAuth '; for(var key in oauth_data) { if (key.indexOf('oauth_') === -1) continue; header_value += this.percentEncode(key) + '="' + this.percentEncode(oauth_data[key]) + '"' + this.parameter_seperator; } return { Authorization: header_value.substr(0, header_value.length - this.parameter_seperator.length) //cut the last chars }; }; /** * Create a random word characters string with input length * #return {String} a random word characters string */ OAuth.prototype.getNonce = function() { var word_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; var result = ''; for(var i = 0; i < this.nonce_length; i++) { result += word_characters[parseInt(Math.random() * word_characters.length, 10)]; } return result; }; /** * Get Current Unix TimeStamp * #return {Int} current unix timestamp */ OAuth.prototype.getTimeStamp = function() { return parseInt(new Date().getTime()/1000, 10); }; ////////////////////// HELPER FUNCTIONS ////////////////////// /** * Merge object * #param {Object} obj1 * #param {Object} obj2 * #return {Object} */ OAuth.prototype.mergeObject = function(obj1, obj2) { var merged_obj = obj1; for(var key in obj2) { merged_obj[key] = obj2[key]; } return merged_obj; }; /** * Sort object by key * #param {Object} data * #return {Object} sorted object */ OAuth.prototype.sortObject = function(data) { var keys = Object.keys(data); var result = {}; keys.sort(); for(var i = 0; i < keys.length; i++) { var key = keys[i]; result[key] = data[key]; } return result; };