diff --git a/package.json b/package.json index 57cc61aab7..f4817d7199 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "test-multi": "karma start $KARMAFLAGS --single-run=false" }, "dependencies": { + "browser-request": "^0.3.3", "classnames": "^2.1.2", "draft-js": "^0.7.0", "draft-js-export-html": "^0.2.2", diff --git a/src/ScalarAuthClient.js b/src/ScalarAuthClient.js new file mode 100644 index 0000000000..67607b4996 --- /dev/null +++ b/src/ScalarAuthClient.js @@ -0,0 +1,47 @@ +/* +Copyright 2016 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +var q = require("q"); +var request = require('browser-request'); + +var SdkConfig = require('./SdkConfig'); + +class ScalarAuthClient { + getScalarToken(openid_token_object) { + var defer = q.defer(); + + var scalar_rest_url = SdkConfig.get().integrations_rest_url; + request({ + method: 'POST', + uri: scalar_rest_url+'/register', + body: openid_token_object, + json: true, + }, (err, response, body) => { + if (err) { + defer.reject(err); + } else if (response.statusCode / 100 !== 2) { + defer.reject({statusCode: response.statusCode}); + } else { + defer.resolve(body.access_token); + } + }); + + return defer.promise; + } +} + +module.exports = ScalarAuthClient; + diff --git a/src/SdkConfig.js b/src/SdkConfig.js index 46c2b818b8..1452aaa64b 100644 --- a/src/SdkConfig.js +++ b/src/SdkConfig.js @@ -16,11 +16,9 @@ limitations under the License. var DEFAULTS = { // URL to a page we show in an iframe to configure integrations - //integrations_ui_url: "https://scalar.vector.im/", - integrations_ui_url: "http://127.0.0.1:5051/", + integrations_ui_url: "https://scalar.vector.im/", // Base URL to the REST interface of the integrations server - //integrations_rest_url: "https://scalar.vector.im/api", - integrations_rest_url: "http://127.0.0.1:5050", + integrations_rest_url: "https://scalar.vector.im/api", }; class SdkConfig { diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 33e6499e21..c9169e0685 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -19,6 +19,7 @@ var url = require('url'); var Favico = require('favico.js'); var MatrixClientPeg = require("../../MatrixClientPeg"); +var SdkConfig = require("../../SdkConfig"); var Notifier = require("../../Notifier"); var ContextualMenu = require("./ContextualMenu"); var RoomListSorter = require("../../RoomListSorter"); @@ -140,6 +141,7 @@ module.exports = React.createClass({ }, componentWillMount: function() { + SdkConfig.put(this.props.config); this.favicon = new Favico({animation: 'none'}); // Stashed guest credentials if the user logs out diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 89146229fa..4a044cb325 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -34,7 +34,11 @@ const LABS_FEATURES = [ { name: 'End-to-End Encryption', id: 'e2e_encryption' - } + }, + { + name: 'Integration Management', + id: 'integration_management' + }, ]; // if this looks like a release, use the 'version' from package.json; else use diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index c996719614..c3dd3338ff 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -17,10 +17,12 @@ limitations under the License. var q = require("q"); var React = require('react'); var MatrixClientPeg = require('../../../MatrixClientPeg'); +var SdkConfig = require('../../../SdkConfig'); var sdk = require('../../../index'); var Modal = require('../../../Modal'); var ObjectUtils = require("../../../ObjectUtils"); var dis = require("../../../dispatcher"); +var ScalarAuthClient = require("../../../ScalarAuthClient"); var UserSettingsStore = require('../../../UserSettingsStore'); // parse a string as an integer; if the input is undefined, or cannot be parsed @@ -73,6 +75,8 @@ module.exports = React.createClass({ // Default to false if it's undefined, otherwise react complains about changing // components from uncontrolled to controlled isRoomPublished: this._originalIsRoomPublished || false, + scalar_token: null, + scalar_error: null, }; }, @@ -86,6 +90,12 @@ module.exports = React.createClass({ console.error("Failed to get room visibility: " + err); }); + this.getScalarToken().done((token) => { + this.setState({scalar_token: token}); + }, (err) => { + this.setState({scalar_error: err}); + }); + dis.dispatch({ action: 'ui_opacity', sideOpacity: 0.3, @@ -398,6 +408,37 @@ module.exports = React.createClass({ roomState.mayClientSendStateEvent("m.room.guest_access", cli)) }, + getScalarInterfaceUrl: function() { + var url = SdkConfig.get().integrations_ui_url; + url += "?scalar_token=" + encodeURIComponent(this.state.scalar_token); + url += "&room_id=" + encodeURIComponent(this.props.room.roomId); + return url; + }, + + getScalarToken() { + var tok = window.localStorage.getItem("mx_scalar_token"); + if (tok) return q(tok); + + // No saved token, so do the dance to get one. First, we + // need an openid bearer token from the HS. + return MatrixClientPeg.get().getOpenIdToken().then((token_object) => { + // Now we can send that to scalar and exchange it for a scalar token + var scalar_auth_client = new ScalarAuthClient(); + return scalar_auth_client.getScalarToken(token_object); + }).then((token_object) => { + window.localStorage.setItem("mx_scalar_token", token_object); + return token_object; + }); + }, + + onManageIntegrations(ev) { + ev.preventDefault(); + var IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager"); + Modal.createDialog(IntegrationsManager, { + src: this.state.scalar_token ? this.getScalarInterfaceUrl() : null + }, ""); + }, + _renderEncryptionSection: function() { if (!UserSettingsStore.isFeatureEnabled("e2e_encryption")) { return null; @@ -430,7 +471,6 @@ module.exports = React.createClass({ ); }, - render: function() { // TODO: go through greying out things you don't have permission to change // (or turning them into informative stuff) @@ -440,6 +480,7 @@ module.exports = React.createClass({ var UrlPreviewSettings = sdk.getComponent("room_settings.UrlPreviewSettings"); var EditableText = sdk.getComponent('elements.EditableText'); var PowerSelector = sdk.getComponent('elements.PowerSelector'); + var Loader = sdk.getComponent("elements.Spinner") var cli = MatrixClientPeg.get(); var roomState = this.props.room.currentState; @@ -577,6 +618,23 @@ module.exports = React.createClass({ } + var integrations_section; + if (UserSettingsStore.isFeatureEnabled("integration_management")) { + if (this.state.scalar_token) { + integrations_section = ( +
+ ); + } else if (this.state.scalar_error) { + integrations_section ={ this.props.room.roomId }
-
);
}