From 59a9f277ba8ea888e3deaa2134af588fcf8c5c9b Mon Sep 17 00:00:00 2001 From: Dima Voytenko Date: Fri, 15 Jan 2016 17:34:49 -0800 Subject: [PATCH] Add AUTH var substitutions to pingback/login URLs. --- extensions/amp-access/0.1/amp-access.js | 40 +++++++++++++++---- .../amp-access/0.1/test/test-amp-access.js | 35 ++++++++++++---- extensions/amp-access/amp-access.md | 13 ++++-- src/url-replacements.js | 4 +- test/functional/test-url-replacements.js | 40 +++++++++++++++++++ 5 files changed, 110 insertions(+), 22 deletions(-) diff --git a/extensions/amp-access/0.1/amp-access.js b/extensions/amp-access/0.1/amp-access.js index 5801da62b247..b46457bbf452 100644 --- a/extensions/amp-access/0.1/amp-access.js +++ b/extensions/amp-access/0.1/amp-access.js @@ -144,6 +144,9 @@ export class AccessService { /** @private {?Promise} */ this.readerIdPromise_ = null; + /** @private {?JSONObject} */ + this.authResponse_ = null; + /** @private {!Promise} */ this.firstAuthorizationPromise_ = new Promise(resolve => { /** @private {!Promise} */ @@ -277,14 +280,24 @@ export class AccessService { /** * @param {string} url + * @param {boolean} useAuthData Allows `AUTH(field)` URL var substitutions. * @return {!Promise} * @private */ - buildUrl_(url) { + buildUrl_(url, useAuthData) { return this.getReaderId_().then(readerId => { - return this.urlReplacements_.expand(url, { + const vars = { 'READER_ID': readerId - }); + }; + if (useAuthData) { + vars['AUTHDATA'] = field => { + if (this.authResponse_) { + return this.authResponse_[field]; + } + return undefined; + }; + } + return this.urlReplacements_.expand(url, vars); }); } @@ -301,12 +314,14 @@ export class AccessService { log.fine(TAG, 'Start authorization via ', this.config_.authorization); this.toggleTopClass_('amp-access-loading', true); - return this.buildUrl_(this.config_.authorization).then(url => { + const promise = this.buildUrl_( + this.config_.authorization, /* useAuthData */ false); + return promise.then(url => { log.fine(TAG, 'Authorization URL: ', url); return this.xhr_.fetchJson(url, {credentials: 'include'}); }).then(response => { log.fine(TAG, 'Authorization response: ', response); - this.firstAuthorizationResolver_(); + this.setAuthResponse_(response); this.toggleTopClass_('amp-access-loading', false); return new Promise((resolve, reject) => { onDocumentReady(this.win.document, () => { @@ -319,6 +334,15 @@ export class AccessService { }); } + /** + * @param {!JSONObject} authResponse + * @private + */ + setAuthResponse_(authResponse) { + this.authResponse_ = authResponse; + this.firstAuthorizationResolver_(); + } + /** * @param {!JSONObjectDef} response * @return {!Promise} @@ -515,7 +539,9 @@ export class AccessService { log.fine(TAG, 'Ignore pingback'); return Promise.resolve(); } - return this.buildUrl_(this.config_.pingback).then(url => { + const promise = this.buildUrl_( + this.config_.pingback, /* useAuthData */ true); + return promise.then(url => { log.fine(TAG, 'Pingback URL: ', url); return this.xhr_.sendSignal(url, { method: 'POST', @@ -567,7 +593,7 @@ export class AccessService { log.fine(TAG, 'Start login'); const urlPromise = this.buildUrl_(assert(this.config_.login, - 'Login URL is not configured')); + 'Login URL is not configured'), /* useAuthData */ true); this.loginPromise_ = this.openLoginDialog_(urlPromise).then(result => { log.fine(TAG, 'Login dialog completed: ', result); this.loginPromise_ = null; diff --git a/extensions/amp-access/0.1/test/test-amp-access.js b/extensions/amp-access/0.1/test/test-amp-access.js index 27be63ae95cb..e973f3e055ea 100644 --- a/extensions/amp-access/0.1/test/test-amp-access.js +++ b/extensions/amp-access/0.1/test/test-amp-access.js @@ -298,6 +298,8 @@ describe('AccessService authorization', () => { expect(document.documentElement).not.to.have.class('amp-access-loading'); expect(elementOn).not.to.have.attribute('amp-access-hide'); expect(elementOff).to.have.attribute('amp-access-hide'); + expect(service.authResponse_).to.exist; + expect(service.authResponse_.access).to.be.true; }); }); @@ -536,7 +538,7 @@ describe('AccessService pingback', () => { configElement.setAttribute('type', 'application/json'); configElement.textContent = JSON.stringify({ 'authorization': 'https://acme.com/a?rid=READER_ID', - 'pingback': 'https://acme.com/p?rid=READER_ID', + 'pingback': 'https://acme.com/p?rid=READER_ID&type=AUTHDATA(type)', 'login': 'https://acme.com/l?rid=READER_ID' }); document.body.appendChild(configElement); @@ -724,13 +726,30 @@ describe('AccessService pingback', () => { it('should send POST pingback', () => { expectGetReaderId('reader1'); xhrMock.expects('sendSignal') - .withExactArgs('https://acme.com/p?rid=reader1', sinon.match(init => { - return (init.method == 'POST' && - init.credentials == 'include' && - init.body == '' && - init.headers['Content-Type'] == - 'application/x-www-form-urlencoded'); - })) + .withExactArgs('https://acme.com/p?rid=reader1&type=', + sinon.match(init => { + return (init.method == 'POST' && + init.credentials == 'include' && + init.body == '' && + init.headers['Content-Type'] == + 'application/x-www-form-urlencoded'); + })) + .returns(Promise.resolve()) + .once(); + return service.reportViewToServer_().then(() => { + return 'SUCCESS'; + }, error => { + return 'ERROR ' + error; + }).then(result => { + expect(result).to.equal('SUCCESS'); + }); + }); + + it('should resolve AUTH vars in POST pingback', () => { + expectGetReaderId('reader1'); + service.setAuthResponse_({type: 'premium'}); + xhrMock.expects('sendSignal') + .withArgs('https://acme.com/p?rid=reader1&type=premium') .returns(Promise.resolve()) .once(); return service.reportViewToServer_().then(() => { diff --git a/extensions/amp-access/amp-access.md b/extensions/amp-access/amp-access.md index c9583b334a31..7fec9bebc6fc 100644 --- a/extensions/amp-access/amp-access.md +++ b/extensions/amp-access/amp-access.md @@ -101,7 +101,7 @@ Here’s an example of the AMP Access configuration: ```html