diff --git a/src/ScalarAuthClient.js b/src/ScalarAuthClient.js
new file mode 100644
index 0000000000..0607e072ac
--- /dev/null
+++ b/src/ScalarAuthClient.js
@@ -0,0 +1,45 @@
+/*
+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 {
+ defer.resolve(body);
+ }
+ });
+
+ return defer.promise;
+ }
+}
+
+module.exports = ScalarAuthClient;
+
diff --git a/src/SdkConfig.js b/src/SdkConfig.js
new file mode 100644
index 0000000000..1452aaa64b
--- /dev/null
+++ b/src/SdkConfig.js
@@ -0,0 +1,45 @@
+/*
+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 DEFAULTS = {
+ // URL to a page we show in an iframe to configure integrations
+ 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",
+};
+
+class SdkConfig {
+
+ static get() {
+ return global.mxReactSdkConfig;
+ }
+
+ static put(cfg) {
+ var defaultKeys = Object.keys(DEFAULTS);
+ for (var i = 0; i < defaultKeys.length; ++i) {
+ if (cfg[defaultKeys[i]] === undefined) {
+ cfg[defaultKeys[i]] = DEFAULTS[defaultKeys[i]];
+ }
+ }
+ global.mxReactSdkConfig = cfg;
+ }
+
+ static unset() {
+ global.mxReactSdkConfig = undefined;
+ }
+}
+
+module.exports = SdkConfig;
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 08b7866b1c..4f5cbb0050 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");
@@ -119,6 +120,7 @@ module.exports = React.createClass({
},
componentWillMount: function() {
+ SdkConfig.put(this.props.config);
this.favicon = new Favico({animation: 'none'});
},
diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js
index fd8bcbfe96..86dfbcf886 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");
module.exports = React.createClass({
displayName: 'RoomSettings',
@@ -71,6 +73,10 @@ module.exports = React.createClass({
console.error("Failed to get room visibility: " + err);
});
+ this.getScalarToken().done((token) => {
+ this.setState({scalar_token: token});
+ });
+
dis.dispatch({
action: 'ui_opacity',
sideOpacity: 0.3,
@@ -359,6 +365,28 @@ module.exports = React.createClass({
roomState.mayClientSendStateEvent("m.room.guest_access", cli))
},
+ getScalarInterfaceUrl: function() {
+ var url = SdkConfig.get().integrations_ui_url;
+ url += "?token=" + this.state.scalar_token;
+ 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;
+ });
+ },
+
render: function() {
// TODO: go through greying out things you don't have permission to change
// (or turning them into informative stuff)
@@ -367,6 +395,7 @@ module.exports = React.createClass({
var ColorSettings = sdk.getComponent("room_settings.ColorSettings");
var EditableText = sdk.getComponent('elements.EditableText');
var PowerSelector = sdk.getComponent('elements.PowerSelector');
+ var Loader = sdk.getComponent("elements.Spinner")
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
var events_levels = (power_levels ? power_levels.getContent().events : {}) || {};
@@ -533,6 +562,13 @@ module.exports = React.createClass({
}
+ var integrations_section;
+ if (this.state.scalar_token) {
+ integrations_section = ;
+ } else {
+ integrations_section =
{ this.props.room.roomId }