Implement OpenID token fetch from Jitsi widget
Using MSC1960 to fetch an OpenID token via postmessage API. This is needed for Jitsi openidtoken-jwt auth.
This commit is contained in:
parent
5108697ac8
commit
8534328921
1 changed files with 73 additions and 12 deletions
|
@ -18,8 +18,9 @@ limitations under the License.
|
||||||
require("./index.scss");
|
require("./index.scss");
|
||||||
|
|
||||||
import * as qs from 'querystring';
|
import * as qs from 'querystring';
|
||||||
import { Capability, WidgetApi } from "matrix-react-sdk/src/widgets/WidgetApi";
|
import {Capability, KnownWidgetActions, WidgetApi} from 'matrix-react-sdk/src/widgets/WidgetApi';
|
||||||
import { KJUR } from "jsrsasign";
|
import {KJUR} from 'jsrsasign';
|
||||||
|
import {objectClone} from 'matrix-react-sdk/lib/utils/objects';
|
||||||
|
|
||||||
// Dev note: we use raw JS without many dependencies to reduce bundle size.
|
// Dev note: we use raw JS without many dependencies to reduce bundle size.
|
||||||
// We do not need all of React to render a Jitsi conference.
|
// We do not need all of React to render a Jitsi conference.
|
||||||
|
@ -36,9 +37,54 @@ let avatarUrl: string;
|
||||||
let userId: string;
|
let userId: string;
|
||||||
let jitsiAuth: string;
|
let jitsiAuth: string;
|
||||||
let roomId: string;
|
let roomId: string;
|
||||||
|
let openIDToken: string;
|
||||||
|
|
||||||
let widgetApi: WidgetApi;
|
let widgetApi: WidgetApi;
|
||||||
|
|
||||||
|
function processOpenIDMessage(msg) {
|
||||||
|
const data = (msg.action === 'get_openid') ? msg.response : msg.data;
|
||||||
|
// TODO: just use data.state once https://github.com/matrix-org/matrix-react-sdk/pull/5172 is out
|
||||||
|
const result = (data.state !== undefined) ? data.state :
|
||||||
|
(data.success === true) ? 'allowed' : 'blocked';
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case 'allowed':
|
||||||
|
console.info('Successfully got OpenID credentials.');
|
||||||
|
openIDToken = data.access_token;
|
||||||
|
// Send a response if this was not a response
|
||||||
|
if (msg.action === 'openid_credentials') {
|
||||||
|
const request = objectClone(msg);
|
||||||
|
request.response = {};
|
||||||
|
window.parent.postMessage(request, '*');
|
||||||
|
}
|
||||||
|
enableJoinButton();
|
||||||
|
break;
|
||||||
|
case 'blocked':
|
||||||
|
console.warn('OpenID credentials request was blocked by user.');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements processing OpenID token requests as per MSC1960
|
||||||
|
*/
|
||||||
|
function onWidgetMessage(msg) {
|
||||||
|
const data = msg.data;
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (data.action) {
|
||||||
|
case 'get_openid':
|
||||||
|
case 'openid_credentials':
|
||||||
|
processOpenIDMessage(data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(async function() {
|
(async function() {
|
||||||
try {
|
try {
|
||||||
// The widget's options are encoded into the fragment to avoid leaking info to the server. The widget
|
// The widget's options are encoded into the fragment to avoid leaking info to the server. The widget
|
||||||
|
@ -78,11 +124,21 @@ let widgetApi: WidgetApi;
|
||||||
if (widgetApi) {
|
if (widgetApi) {
|
||||||
await widgetApi.waitReady();
|
await widgetApi.waitReady();
|
||||||
await widgetApi.setAlwaysOnScreen(false); // start off as detachable from the screen
|
await widgetApi.setAlwaysOnScreen(false); // start off as detachable from the screen
|
||||||
|
|
||||||
|
if (jitsiAuth === 'openidtoken-jwt') {
|
||||||
|
window.addEventListener('message', onWidgetMessage);
|
||||||
|
widgetApi.callAction(
|
||||||
|
KnownWidgetActions.GetOpenIDCredentials,
|
||||||
|
{},
|
||||||
|
(response) => {console.log(response);},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
enableJoinButton();
|
||||||
|
}
|
||||||
|
// TODO: register widgetApi listeners for PTT controls (https://github.com/vector-im/riot-web/issues/12795)
|
||||||
|
} else {
|
||||||
|
enableJoinButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: register widgetApi listeners for PTT controls (https://github.com/vector-im/riot-web/issues/12795)
|
|
||||||
|
|
||||||
document.getElementById("joinButton").onclick = () => joinConference();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error setting up Jitsi widget", e);
|
console.error("Error setting up Jitsi widget", e);
|
||||||
document.getElementById("jitsiContainer").innerText = "Failed to load Jitsi widget";
|
document.getElementById("jitsiContainer").innerText = "Failed to load Jitsi widget";
|
||||||
|
@ -90,6 +146,11 @@ let widgetApi: WidgetApi;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
function enableJoinButton() {
|
||||||
|
document.getElementById("joinButton").onclick = () => joinConference();
|
||||||
|
}
|
||||||
|
|
||||||
function switchVisibleContainers() {
|
function switchVisibleContainers() {
|
||||||
inConference = !inConference;
|
inConference = !inConference;
|
||||||
document.getElementById("jitsiContainer").style.visibility = inConference ? 'unset' : 'hidden';
|
document.getElementById("jitsiContainer").style.visibility = inConference ? 'unset' : 'hidden';
|
||||||
|
@ -107,14 +168,13 @@ function createJWTToken() {
|
||||||
// Payload
|
// Payload
|
||||||
const payload = {
|
const payload = {
|
||||||
// TODO change this to refer to spec?
|
// TODO change this to refer to spec?
|
||||||
iss: "app_id",
|
iss: 'app_id',
|
||||||
sub: jitsiDomain,
|
sub: jitsiDomain,
|
||||||
aud: `https://${jitsiDomain}`,
|
aud: `https://${jitsiDomain}`,
|
||||||
room: "*",
|
room: "*",
|
||||||
context: {
|
context: {
|
||||||
matrix: {
|
matrix: {
|
||||||
// TODO openid token retrieved as per MSC1960
|
token: openIDToken,
|
||||||
token: "foobar",
|
|
||||||
room_id: roomId,
|
room_id: roomId,
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
|
@ -128,10 +188,10 @@ function createJWTToken() {
|
||||||
// to transport data to Prosody in the Jitsi stack.
|
// to transport data to Prosody in the Jitsi stack.
|
||||||
// See TODO add link
|
// See TODO add link
|
||||||
return KJUR.jws.JWS.sign(
|
return KJUR.jws.JWS.sign(
|
||||||
"HS256",
|
'HS256',
|
||||||
JSON.stringify(header),
|
JSON.stringify(header),
|
||||||
JSON.stringify(payload),
|
JSON.stringify(payload),
|
||||||
"notused",
|
'notused',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +219,7 @@ function joinConference() { // event handler bound in HTML
|
||||||
},
|
},
|
||||||
jwt: undefined,
|
jwt: undefined,
|
||||||
};
|
};
|
||||||
if (jitsiAuth === "openidtoken-jwt") {
|
if (jitsiAuth === 'penidtoken-jwt') {
|
||||||
options.jwt = createJWTToken();
|
options.jwt = createJWTToken();
|
||||||
}
|
}
|
||||||
const meetApi = new JitsiMeetExternalAPI(jitsiDomain, options);
|
const meetApi = new JitsiMeetExternalAPI(jitsiDomain, options);
|
||||||
|
@ -168,6 +228,7 @@ function joinConference() { // event handler bound in HTML
|
||||||
if (userId) meetApi.executeCommand("email", userId);
|
if (userId) meetApi.executeCommand("email", userId);
|
||||||
|
|
||||||
meetApi.on("readyToClose", () => {
|
meetApi.on("readyToClose", () => {
|
||||||
|
window.removeEventListener('message', onWidgetMessage);
|
||||||
switchVisibleContainers();
|
switchVisibleContainers();
|
||||||
|
|
||||||
// noinspection JSIgnoredPromiseFromCall
|
// noinspection JSIgnoredPromiseFromCall
|
||||||
|
|
Loading…
Reference in a new issue