diff --git a/package.json b/package.json index db623ae35..2b3d5e04e 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "build": "babel -s -d lib src && rimraf dist && mkdir dist && browserify -d browser-index.js | exorcist dist/browser-matrix.js.map > dist/browser-matrix.js && uglifyjs -c -m -o dist/browser-matrix.min.js --source-map dist/browser-matrix.min.js.map --in-source-map dist/browser-matrix.js.map dist/browser-matrix.js", "dist": "npm run build", "watch": "watchify -d browser-index.js -o 'exorcist dist/browser-matrix.js.map > dist/browser-matrix.js' -v", - "lint": "eslint --max-warnings 112 src spec", + "lint": "eslint --max-warnings 110 src spec", "prepublish": "npm run build && git rev-parse HEAD > git-revision.txt" }, "repository": { diff --git a/spec/integ/matrix-client-methods.spec.js b/spec/integ/matrix-client-methods.spec.js index 598a02f47..93048882c 100644 --- a/spec/integ/matrix-client-methods.spec.js +++ b/spec/integ/matrix-client-methods.spec.js @@ -51,7 +51,10 @@ describe("MatrixClient", function() { ).check(function(req) { expect(req.rawData).toEqual(buf); expect(req.queryParams.filename).toEqual("hi.txt"); - expect(req.queryParams.access_token).toEqual(accessToken); + if (!(req.queryParams.access_token == accessToken || + req.headers["Authorization"] == "Bearer " + accessToken)) { + expect(true).toBe(false); + } expect(req.headers["Content-Type"]).toEqual("text/plain"); expect(req.opts.json).toBeFalsy(); expect(req.opts.timeout).toBe(undefined); diff --git a/src/base-apis.js b/src/base-apis.js index 978e2804e..8c666faf6 100644 --- a/src/base-apis.js +++ b/src/base-apis.js @@ -54,6 +54,8 @@ const utils = require("./utils"); * to all requests with this client. Useful for application services which require * ?user_id=. * + * @param {boolean} [opts.useAuthorizationHeader = false] Set to true to use + * Authorization header instead of query param to send the access token to the server. */ function MatrixBaseApis(opts) { utils.checkObjectHasKeys(opts, ["baseUrl", "request"]); @@ -70,6 +72,7 @@ function MatrixBaseApis(opts) { onlyData: true, extraParams: opts.queryParams, localTimeoutMs: opts.localTimeoutMs, + useAuthorizationHeader: opts.useAuthorizationHeader, }; this._http = new httpApi.MatrixHttpApi(this, httpOpts); diff --git a/src/client.js b/src/client.js index 7beb8c00f..85e6fa08f 100644 --- a/src/client.js +++ b/src/client.js @@ -99,6 +99,9 @@ try { * @param {Number=} opts.localTimeoutMs Optional. The default maximum amount of * time to wait before timing out HTTP requests. If not specified, there is no timeout. * + * @param {boolean} [opts.useAuthorizationHeader = false] Set to true to use + * Authorization header instead of query param to send the access token to the server. + * * @param {boolean} [opts.timelineSupport = false] Set to true to enable * improved timeline support ({@link * module:client~MatrixClient#getEventTimeline getEventTimeline}). It is diff --git a/src/http-api.js b/src/http-api.js index 69b66786b..daf7113c5 100644 --- a/src/http-api.js +++ b/src/http-api.js @@ -66,7 +66,7 @@ module.exports.PREFIX_MEDIA_R0 = "/_matrix/media/r0"; * @param {string} opts.prefix Required. The matrix client prefix to use, e.g. * '/_matrix/client/r0'. See PREFIX_R0 and PREFIX_UNSTABLE for constants. * - * @param {bool=} opts.onlyData True to return only the 'data' component of the + * @param {boolean} opts.onlyData True to return only the 'data' component of the * response (e.g. the parsed HTTP body). If false, requests will return an * object with the properties code, headers and data. * @@ -76,12 +76,15 @@ module.exports.PREFIX_MEDIA_R0 = "/_matrix/media/r0"; * requests. * @param {Number=} opts.localTimeoutMs The default maximum amount of time to wait * before timing out the request. If not specified, there is no timeout. + * @param {boolean} [opts.useAuthorizationHeader = false] Set to true to use + * Authorization header instead of query param to send the access token to the server. */ module.exports.MatrixHttpApi = function MatrixHttpApi(event_emitter, opts) { utils.checkObjectHasKeys(opts, ["baseUrl", "request", "prefix"]); opts.onlyData = opts.onlyData || false; this.event_emitter = event_emitter; this.opts = opts; + this.useAuthorizationHeader = Boolean(opts.useAuthorizationHeader); this.uploads = []; }; @@ -366,7 +369,8 @@ module.exports.MatrixHttpApi.prototype = { * * @param {Object} data The HTTP JSON body. * - * @param {Object=} opts additional options + * @param {Object|Number=} opts additional options. If a number is specified, + * this is treated as `opts.localTimeoutMs`. * * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before * timing out the request. If not specified, there is no timeout. @@ -387,16 +391,37 @@ module.exports.MatrixHttpApi.prototype = { if (!queryParams) { queryParams = {}; } - if (!queryParams.access_token) { - queryParams.access_token = this.opts.accessToken; + if (this.useAuthorizationHeader) { + if (isFinite(opts)) { + // opts used to be localTimeoutMs + opts = { + localTimeoutMs: opts, + }; + } + if (!opts) { + opts = {}; + } + if (!opts.headers) { + opts.headers = {}; + } + if (!opts.headers.Authorization) { + opts.headers.Authorization = "Bearer " + this.opts.accessToken; + } + if (queryParams.access_token) { + delete queryParams.access_token; + } + } else { + if (!queryParams.access_token) { + queryParams.access_token = this.opts.accessToken; + } } - const request_promise = this.request( + const requestPromise = this.request( callback, method, path, queryParams, data, opts, ); const self = this; - request_promise.catch(function(err) { + requestPromise.catch(function(err) { if (err.errcode == 'M_UNKNOWN_TOKEN') { self.event_emitter.emit("Session.logged_out"); } @@ -404,7 +429,7 @@ module.exports.MatrixHttpApi.prototype = { // return the original promise, otherwise tests break due to it having to // go around the event loop one more time to process the result of the request - return request_promise; + return requestPromise; }, /**