mirror of
https://github.com/ToolJet/ToolJet
synced 2026-04-21 13:37:28 +00:00
[hotfix] Invitation URLs and SSO redirection URLs are not subpath compatible (#7155)
* Added subpath compatible code to the invitation URL generation * fix: sharable app link - launch app url * Added PR changes
This commit is contained in:
parent
36efa1be11
commit
4f9f555187
12 changed files with 61 additions and 30 deletions
|
|
@ -14,7 +14,9 @@ export default function GoogleSSOLoginButton(props) {
|
|||
e.preventDefault();
|
||||
const { client_id } = props.configs;
|
||||
const authUrl = buildURLWithQuery('https://accounts.google.com/o/oauth2/auth', {
|
||||
redirect_uri: `${window.public_config?.TOOLJET_HOST}/sso/google${props.configId ? `/${props.configId}` : ''}`,
|
||||
redirect_uri: `${window.public_config?.TOOLJET_HOST}${window.public_config?.SUB_PATH ?? '/'}sso/google${
|
||||
props.configId ? `/${props.configId}` : ''
|
||||
}`,
|
||||
response_type: 'id_token',
|
||||
scope: 'email profile',
|
||||
client_id,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import Textarea from '@/_ui/Textarea';
|
|||
import { withTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getPrivateRoute } from '@/_helpers/routes';
|
||||
import { getSubpath } from '@/_helpers/utils';
|
||||
|
||||
class ManageAppUsersComponent extends React.Component {
|
||||
constructor(props) {
|
||||
|
|
@ -133,7 +134,7 @@ class ManageAppUsersComponent extends React.Component {
|
|||
render() {
|
||||
const { isLoading, app, slugError, isSlugVerificationInProgress } = this.state;
|
||||
const appId = app.id;
|
||||
const appLink = `${window.public_config?.TOOLJET_HOST}/applications/`;
|
||||
const appLink = `${window.public_config?.TOOLJET_HOST}${getSubpath() ? getSubpath() : ''}/applications/`;
|
||||
const shareableLink = appLink + (this.props.slug || appId);
|
||||
const slugButtonClass = isSlugVerificationInProgress ? '' : slugError !== null ? 'is-invalid' : 'is-valid';
|
||||
const embeddableLink = `<iframe width="560" height="315" src="${appLink}${this.props.slug}" title="Tooljet app - ${this.props.slug}" frameborder="0" allowfullscreen></iframe>`;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import SolidIcon from '@/_ui/Icon/SolidIcons';
|
|||
import BulkIcon from '@/_ui/Icon/BulkIcons';
|
||||
|
||||
import { getPrivateRoute } from '@/_helpers/routes';
|
||||
import { getSubpath } from '@/_helpers/utils';
|
||||
const { defaultIcon } = configs;
|
||||
|
||||
export default function AppCard({
|
||||
|
|
@ -149,7 +150,9 @@ export default function AppCard({
|
|||
)}
|
||||
onClick={() => {
|
||||
if (app?.current_version_id) {
|
||||
window.open(urlJoin(window.public_config?.TOOLJET_HOST, `/applications/${app.slug}`));
|
||||
window.open(
|
||||
urlJoin(window.public_config?.TOOLJET_HOST, getSubpath() ?? '', `/applications/${app.slug}`)
|
||||
);
|
||||
} else {
|
||||
navigate(app?.current_version_id ? `/applications/${app.slug}` : '');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,11 +205,13 @@ class ManageOrgUsersComponent extends React.Component {
|
|||
if (user.account_setup_token) {
|
||||
return urlJoin(
|
||||
window.public_config?.TOOLJET_HOST,
|
||||
window.public_config?.SUB_PATH ?? '',
|
||||
`/invitations/${user.account_setup_token}/workspaces/${user.invitation_token}?oid=${authenticationService?.currentSessionValue.current_organization_id}`
|
||||
);
|
||||
}
|
||||
return urlJoin(
|
||||
window.public_config?.TOOLJET_HOST,
|
||||
window.public_config?.SUB_PATH ?? '',
|
||||
`/organization-invitations/${user.invitation_token}?oid=${authenticationService?.currentSessionValue.current_organization_id}`
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -166,7 +166,9 @@ export function GeneralSettings({ settings, updateData, instanceSettings, darkMo
|
|||
|
||||
<div className="d-flex justify-content-between form-control align-items-center">
|
||||
<p id="login-url" data-cy="workspace-login-url">
|
||||
{`${window.public_config?.TOOLJET_HOST}/login/${authenticationService?.currentSessionValue?.current_organization_id}`}
|
||||
{`${window.public_config?.TOOLJET_HOST}${
|
||||
window.public_config?.SUB_PATH ? window.public_config?.SUB_PATH : '/'
|
||||
}login/${authenticationService?.currentSessionValue?.current_organization_id}`}
|
||||
</p>
|
||||
<SolidIcon name="copy" width="16" onClick={() => copyFunction('login-url')} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -152,10 +152,9 @@ export function Git({ settings, updateData }) {
|
|||
{t('header.organization.menus.manageSSO.github.redirectUrl', 'Redirect URL')}
|
||||
</label>
|
||||
<div className="d-flex justify-content-between form-control align-items-center">
|
||||
<p
|
||||
data-cy="redirect-url"
|
||||
id="redirect-url"
|
||||
>{`${window.public_config?.TOOLJET_HOST}/sso/git/${configId}`}</p>
|
||||
<p data-cy="redirect-url" id="redirect-url">{`${window.public_config?.TOOLJET_HOST}${
|
||||
window.public_config?.SUB_PATH ? window.public_config?.SUB_PATH : '/'
|
||||
}sso/git/${configId}`}</p>
|
||||
<SolidIcon name="copy" width="16" onClick={() => copyFunction('redirect-url')} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -113,10 +113,9 @@ export function Google({ settings, updateData }) {
|
|||
{t('header.organization.menus.manageSSO.google.redirectUrl', 'Redirect URL')}
|
||||
</label>
|
||||
<div className="d-flex justify-content-between form-control align-items-center">
|
||||
<p
|
||||
data-cy="redirect-url"
|
||||
id="redirect-url"
|
||||
>{`${window.public_config?.TOOLJET_HOST}/sso/google/${configId}`}</p>
|
||||
<p data-cy="redirect-url" id="redirect-url">{`${window.public_config?.TOOLJET_HOST}${
|
||||
window.public_config?.SUB_PATH ? window.public_config?.SUB_PATH : '/'
|
||||
}sso/google/${configId}`}</p>
|
||||
<SolidIcon name="copy" width="16" onClick={() => copyFunction('redirect-url')} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {
|
|||
URL_SSO_SOURCE,
|
||||
WORKSPACE_USER_STATUS,
|
||||
} from 'src/helpers/user_lifecycle';
|
||||
import { dbTransactionWrap, generateNextName } from 'src/helpers/utils.helper';
|
||||
import { dbTransactionWrap, generateInviteURL, generateNextName } from 'src/helpers/utils.helper';
|
||||
import { DeepPartial, EntityManager } from 'typeorm';
|
||||
import { GitOAuthService } from './git_oauth.service';
|
||||
import { GoogleOAuthService } from './google_oauth.service';
|
||||
|
|
@ -316,9 +316,12 @@ export class OauthService {
|
|||
)?.invitationToken;
|
||||
|
||||
return decamelizeKeys({
|
||||
redirectUrl: `${this.configService.get<string>('TOOLJET_HOST')}/invitations/${
|
||||
userDetails.invitationToken
|
||||
}/workspaces/${organizationToken}?oid=${organization.id}&source=${URL_SSO_SOURCE}`,
|
||||
redirectUrl: generateInviteURL(
|
||||
userDetails.invitationToken,
|
||||
organizationToken,
|
||||
organization.id,
|
||||
URL_SSO_SOURCE
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -331,9 +334,7 @@ export class OauthService {
|
|||
manager
|
||||
);
|
||||
return decamelizeKeys({
|
||||
redirectUrl: `${this.configService.get<string>('TOOLJET_HOST')}/invitations/${
|
||||
userDetails.invitationToken
|
||||
}?source=${URL_SSO_SOURCE}`,
|
||||
redirectUrl: generateInviteURL(userDetails.invitationToken, null, null, URL_SSO_SOURCE),
|
||||
});
|
||||
}
|
||||
return await this.authService.generateLoginResultPayload(
|
||||
|
|
|
|||
|
|
@ -144,3 +144,25 @@ export const truncateAndReplace = (name) => {
|
|||
}
|
||||
return name + secondsSinceEpoch;
|
||||
};
|
||||
|
||||
export const generateInviteURL = (
|
||||
invitationToken: string,
|
||||
organizationToken?: string,
|
||||
organizationId?: string,
|
||||
source?: string
|
||||
) => {
|
||||
const host = process.env.TOOLJET_HOST;
|
||||
const subpath = process.env.SUB_PATH;
|
||||
|
||||
return `${host}${subpath ? subpath : '/'}invitations/${invitationToken}${
|
||||
organizationToken ? `/workspaces/${organizationToken}${organizationId ? `?oid=${organizationId}` : ''}` : ''
|
||||
}${source ? `${organizationId ? '&' : '?'}source=${source}` : ''}`;
|
||||
};
|
||||
|
||||
export const generateOrgInviteURL = (organizationToken: string, organizationId?: string) => {
|
||||
const host = process.env.TOOLJET_HOST;
|
||||
const subpath = process.env.SUB_PATH;
|
||||
return `${host}${subpath ? subpath : '/'}organization-invitations/${organizationToken}${
|
||||
organizationId ? `?oid=${organizationId}` : ''
|
||||
}`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { DeepPartial, EntityManager, Repository } from 'typeorm';
|
|||
import { OrganizationUser } from 'src/entities/organization_user.entity';
|
||||
import { CreateAdminDto, CreateUserDto } from '@dto/user.dto';
|
||||
import { AcceptInviteDto } from '@dto/accept-organization-invite.dto';
|
||||
import { dbTransactionWrap, generateNextName } from 'src/helpers/utils.helper';
|
||||
import { dbTransactionWrap, generateInviteURL, generateNextName, generateOrgInviteURL } from 'src/helpers/utils.helper';
|
||||
import {
|
||||
getUserErrorMessages,
|
||||
getUserStatusAndSource,
|
||||
|
|
@ -458,7 +458,8 @@ export class AuthService {
|
|||
user.email,
|
||||
`${user.firstName} ${user.lastName} ?? ''`,
|
||||
user.invitationToken,
|
||||
`${organizationUser.invitationToken}?oid=${organizationUser.organizationId}`
|
||||
`${organizationUser.invitationToken}`,
|
||||
organizationUser.organizationId
|
||||
)
|
||||
.catch((err) => console.error('Error while sending welcome mail', err));
|
||||
throw new UnauthorizedException(
|
||||
|
|
@ -484,13 +485,11 @@ export class AuthService {
|
|||
|
||||
if (!user && organizationUser) {
|
||||
return {
|
||||
redirect_url: `${this.configService.get<string>(
|
||||
'TOOLJET_HOST'
|
||||
)}/organization-invitations/${organizationToken}?oid=${organizationUser.organizationId}`,
|
||||
redirect_url: generateOrgInviteURL(organizationToken, organizationUser.organizationId),
|
||||
};
|
||||
} else if (user && !organizationUser) {
|
||||
return {
|
||||
redirect_url: `${this.configService.get<string>('TOOLJET_HOST')}/invitations/${token}`,
|
||||
redirect_url: generateInviteURL(token),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import handlebars from 'handlebars';
|
||||
import { generateInviteURL, generateOrgInviteURL } from 'src/helpers/utils.helper';
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const nodemailer = require('nodemailer');
|
||||
|
|
@ -70,13 +71,12 @@ export class EmailService {
|
|||
name: string,
|
||||
invitationtoken: string,
|
||||
organizationInvitationToken?: string,
|
||||
organizationId?: string,
|
||||
organizationName?: string,
|
||||
sender?: string
|
||||
) {
|
||||
const subject = 'Welcome to ToolJet';
|
||||
const inviteUrl = `${this.TOOLJET_HOST}/invitations/${invitationtoken}${
|
||||
organizationInvitationToken ? `/workspaces/${organizationInvitationToken}` : ''
|
||||
}`;
|
||||
const inviteUrl = generateInviteURL(invitationtoken, organizationInvitationToken, organizationId);
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
|
@ -117,7 +117,7 @@ export class EmailService {
|
|||
organizationName: string
|
||||
) {
|
||||
const subject = 'Welcome to ToolJet';
|
||||
const inviteUrl = `${this.TOOLJET_HOST}/organization-invitations/${invitationtoken}`;
|
||||
const inviteUrl = generateOrgInviteURL(invitationtoken);
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
|
|
|||
|
|
@ -598,7 +598,8 @@ export class OrganizationsService {
|
|||
user.email,
|
||||
user.firstName,
|
||||
user.invitationToken,
|
||||
`${organizationUser.invitationToken}?oid=${organizationUser.organizationId}`,
|
||||
organizationUser.invitationToken,
|
||||
organizationUser.organizationId,
|
||||
currentOrganization.name,
|
||||
`${currentUser.firstName} ${currentUser.lastName ?? ''}`
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue