fix(cli-serve): OAuth instance cache issue (#1500)

* fix: client id cache issue

* chore: fix originurl

---------

Co-authored-by: a-m-dev <a.mirzaei.dev@gmail.com>
This commit is contained in:
Tobias Åström
2024-03-05 16:39:36 +01:00
committed by GitHub
parent d8b137df82
commit a0dc0f0ce1
12 changed files with 234 additions and 101 deletions

View File

@@ -4,7 +4,6 @@ const fs = require('fs');
const homedir = require('os').homedir();
const chalk = require('chalk');
const express = require('express');
const { Auth, AuthType } = require('@qlik/sdk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
@@ -12,22 +11,11 @@ const WebpackDevServer = require('webpack-dev-server');
const snapshooterFn = require('./snapshot-server');
const snapshotRouter = require('./snapshot-router');
const { OAuthRouter, getAvailableAuthInstance } = require('./oauth-router');
const httpsKeyPath = path.join(homedir, '.certs/key.pem');
const httpsCertPath = path.join(homedir, '.certs/cert.pem');
let authInstance = null;
const getAuthInstance = (returnToOrigin, host, clientId) => {
if (authInstance) return authInstance;
authInstance = new Auth({
authType: AuthType.OAuth2,
host,
clientId,
redirectUri: `${returnToOrigin}/login/callback`,
});
return authInstance;
};
module.exports = async ({
host,
port,
@@ -65,6 +53,7 @@ module.exports = async ({
snapshooter.storeSnapshot(s);
});
const authRouter = OAuthRouter({ originUrl: url });
const snapRouter = snapshotRouter({
base: `${url}${snapshotRoute}`,
snapshotUrl: `${url}/eRender.html`,
@@ -118,6 +107,8 @@ module.exports = async ({
},
onBeforeSetupMiddleware(devServer) {
const { app } = devServer;
app.use('/auth', authRouter);
app.use(snapshotRoute, snapRouter);
if (entryWatcher) {
@@ -173,87 +164,9 @@ module.exports = async ({
});
});
let cachedHost = null;
let cachedClientId = null;
app.get('/oauth', async (req, res) => {
const { host: qHost, clientId: qClientId } = req.query;
if (!cachedHost && !cachedClientId) {
cachedHost = qHost;
cachedClientId = qClientId;
}
const returnTo = `${req.protocol}://${req.get('host')}`;
const instacne = getAuthInstance(returnTo, qHost, qClientId);
const isAuthorized = await instacne.isAuthorized();
if (!isAuthorized) {
const { url: redirectUrl } = await instacne.generateAuthorizationUrl();
res.status(200).json({ redirectUrl });
} else {
const redirectUrl = `${req.protocol}://${req.get(
'host'
)}/app-list?engine_url=wss://${cachedHost}&qlik-client-id=${cachedClientId}&shouldFetchAppList=true`;
cachedHost = null;
cachedClientId = null;
res.redirect(redirectUrl);
}
});
app.get('/login/callback', async (req, res) => {
const authLink = new URL(req.url, `http://${req.headers.host}`).href;
try {
// TODO:
// this is a temp fix in front end side
// (temp workaround of not presisting origin while backend tries to authorize user)
// they need to handle this in qlik-sdk-typescript repo
// and will notify us about when they got fixed it,
// but until then, we need to take care of it here!
authInstance.rest.interceptors.request.use((_req) => {
// eslint-disable-next-line no-param-reassign, dot-notation
_req[1]['headers'] = { origin: url };
return _req;
});
await authInstance.authorize(authLink);
res.redirect(301, '/oauth/');
} catch (err) {
console.log({ err });
res.status(401).send(JSON.stringify(err, null, 2));
}
});
app.get('/getSocketUrl/:appId', async (req, res) => {
const { appId } = req.params;
const webSocketUrl = await authInstance.generateWebsocketUrl(appId, true);
res.status(200).json({ webSocketUrl });
});
app.get('/deauthorize', async (req, res) => {
try {
await authInstance.deauthorize();
res.status(200).json({
deauthorize: true,
});
} catch (error) {
console.log({ error });
}
});
app.get('/isAuthorized', async (req, res) => {
if (!authInstance) {
res.status(200).json({
isAuthorized: false,
});
} else {
const isAuthorized = await authInstance.isAuthorized();
res.status(200).json({
isAuthorized,
});
}
});
app.get('/apps', async (req, res) => {
const appsListUrl = `/items?resourceType=app&limit=30&sort=-updatedAt`;
const { data = [] } = await (await authInstance.rest(appsListUrl)).json();
const { data = [] } = await (await getAvailableAuthInstance().rest(appsListUrl)).json();
res.status(200).json(
data.map((d) => ({
qDocId: d.resourceId,