From 6c147557d73474a4521d0ce056ab5eddc1a8f40d Mon Sep 17 00:00:00 2001 From: Damien Lebrun Date: Sat, 23 Dec 2017 13:14:48 +0000 Subject: [PATCH] Exclude default ports 80/443 from base URL Fix #59. --- oauth-1.0a.d.ts | 23 +++++++++++++++++++++ oauth-1.0a.js | 43 +++++++++++++++++++++++++++++++++++++- test/getBaseUrl.js | 29 ++++++++++++++++++++++++++ test/parseUrl.js | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 test/getBaseUrl.js create mode 100644 test/parseUrl.js diff --git a/oauth-1.0a.d.ts b/oauth-1.0a.d.ts index f40cb3d..fa2bbed 100644 --- a/oauth-1.0a.d.ts +++ b/oauth-1.0a.d.ts @@ -17,6 +17,8 @@ declare class OAuth { signature_metho: string; version: string; + private _urlPattern: RegExp; + constructor(opts?: OAuth.Options); /** @@ -93,6 +95,14 @@ declare class OAuth { */ mergeObject(obj1: T, obj2: U): T & U; + /** + * Parse an URL into its various component. + * + * Does no normalisation but throw if it encounters non-ascii char or if the + * URL does represent a http(s) request. + */ + parseUrl(url: string): OAuth.URL; + /** * Sort an object properties by keys. */ @@ -189,4 +199,17 @@ declare namespace OAuth { secret: string; } + /** + * URL components + */ + export interface URL { + auth: string; + hash: string; + hostname: string; + pathname: string; + port: string; + protocol: 'http' | 'https'; + search: string; + } + } diff --git a/oauth-1.0a.js b/oauth-1.0a.js index 5c15dd4..1d10d52 100644 --- a/oauth-1.0a.js +++ b/oauth-1.0a.js @@ -194,7 +194,18 @@ OAuth.prototype.getSigningKey = function(token_secret) { * @return {String} */ OAuth.prototype.getBaseUrl = function(url) { - return url.split('?')[0]; + var parsed = this.parseUrl(url); + var port = parsed.port; + var protocol = parsed.protocol.toLowerCase(); + + if ( + (port === ':80' && protocol === 'http') || + (port === ':443' && protocol === 'https') + ) { + parsed.port = ''; + } + + return parsed.protocol + '://' + parsed.auth + parsed.hostname + parsed.port + parsed.pathname; }; /** @@ -354,6 +365,36 @@ OAuth.prototype.mergeObject = function(obj1, obj2) { return merged_obj; }; +OAuth.prototype._urlPattern = /^(https?):\/\/([^:]+:[^@]+@)?([^:/?#]+)(\:\d+)?(\/[^?#]*)?(\?[^#]*)?(#.*)?$/; + +/** + * Parse an URL into its various component. + * + * Does no normalisation but throw if it encounters non-ascii char or if the + * URL does represent a http(s) request. + * + * @param {string} url Url to parse + * @returns {object} + */ +OAuth.prototype.parseUrl = function(url) { + var match = this._urlPattern.exec(url); + var components; + + if (match == null || match.len < 8) { + throw new Error('Invalid URL: "' + url + '".'); + } + + return { + protocol: match[1], + auth: match[2] || '', + hostname: match[3], + port: match[4] || '', + pathname: match[5] || '', + search: match[6] || '', + hash: match[7] || '' + }; +}; + /** * Sort object by key * @param {Object} data diff --git a/test/getBaseUrl.js b/test/getBaseUrl.js new file mode 100644 index 0000000..ee7b0ac --- /dev/null +++ b/test/getBaseUrl.js @@ -0,0 +1,29 @@ +var expect = require('chai').expect; +var OAuth = require('../oauth-1.0a'); + +describe('#getBaseUrl', function() { + var oauth = new OAuth({consumer: {}}); + + beforeEach(function () { + oauth = new OAuth({consumer: {}}); + }); + + it('should return base url', function () { + expect(oauth.getBaseUrl('http://example.com/path/')).to.equal('http://example.com/path/'); + expect(oauth.getBaseUrl('http://example.com/path/?foo=bar')).to.equal('http://example.com/path/'); + }); + + it('should exclude default port number', function () { + expect(oauth.getBaseUrl('http://example.com/')).to.equal('http://example.com/'); + expect(oauth.getBaseUrl('http://example.com:80/')).to.equal('http://example.com/'); + expect(oauth.getBaseUrl('https://example.com/')).to.equal('https://example.com/'); + expect(oauth.getBaseUrl('https://example.com:443/')).to.equal('https://example.com/'); + }); + + it('should include non-default port number', function () { + expect(oauth.getBaseUrl('http://example.com:8080/')).to.equal('http://example.com:8080/'); + expect(oauth.getBaseUrl('http://example.com:443/')).to.equal('http://example.com:443/'); + expect(oauth.getBaseUrl('https://example.com:8080/')).to.equal('https://example.com:8080/'); + expect(oauth.getBaseUrl('https://example.com:80/')).to.equal('https://example.com:80/'); + }); +}); diff --git a/test/parseUrl.js b/test/parseUrl.js new file mode 100644 index 0000000..4928ee3 --- /dev/null +++ b/test/parseUrl.js @@ -0,0 +1,51 @@ +var expect = require('chai').expect; +var OAuth = require('../oauth-1.0a'); + +describe('OAuth.parseUrl', function() { + var oauth = new OAuth({consumer: {}}); + + beforeEach(function () { + oauth = new OAuth({consumer: {}}); + }); + + it('should parse protocol', function () { + expect(oauth.parseUrl('http://example.com/').protocol).to.equal('http'); + expect(oauth.parseUrl('https://example.com/').protocol).to.equal('https'); + }); + + it('should parse auth component', function () { + expect(oauth.parseUrl('http://example.com/').auth).to.equal(''); + expect(oauth.parseUrl('http://foo:bar@example.com/').auth).to.equal('foo:bar@'); + }); + + it('should parse hostname component', function () { + expect(oauth.parseUrl('http://example.com/').hostname).to.equal('example.com'); + expect(oauth.parseUrl('http://example.com:8080/').hostname).to.equal('example.com'); + expect(oauth.parseUrl('http://foo:bar@example.com/').hostname).to.equal('example.com'); + }); + + it('should parse port component', function () { + expect(oauth.parseUrl('http://example.com/').port).to.equal(''); + expect(oauth.parseUrl('http://example.com:80/').port).to.equal(':80'); + expect(oauth.parseUrl('http://foo:bar@example.com:80/').port).to.equal(':80'); + }); + + it('should parse pathname component', function () { + expect(oauth.parseUrl('http://example.com').pathname).to.equal(''); + expect(oauth.parseUrl('http://example.com/').pathname).to.equal('/'); + expect(oauth.parseUrl('http://example.com/foo/bar').pathname).to.equal('/foo/bar'); + }); + + it('should parse search component', function () { + expect(oauth.parseUrl('http://example.com').search).to.equal(''); + expect(oauth.parseUrl('http://example.com/?foo').search).to.equal('?foo'); + expect(oauth.parseUrl('http://example.com/?foo#bar').search).to.equal('?foo'); + expect(oauth.parseUrl('http://example.com/?foo?bar').search).to.equal('?foo?bar'); + }); + + it('should parse hash component', function () { + expect(oauth.parseUrl('http://example.com').hash).to.equal(''); + expect(oauth.parseUrl('http://example.com/?foo').hash).to.equal(''); + expect(oauth.parseUrl('http://example.com/?foo#bar').hash).to.equal('#bar'); + }); +});