Add a prompt when interacting with an identity server without terms
This adds a prompt whenever we are about to perform some action on a default identity server (from homeserver .well-known or Riot app config) without terms. This allows the user to abort or trust the server (storing it in account data). Fixes https://github.com/vector-im/riot-web/issues/10557
This commit is contained in:
parent
54cea6a5e3
commit
0fc5108817
4 changed files with 81 additions and 19 deletions
|
@ -17,7 +17,18 @@ limitations under the License.
|
|||
import { createClient, SERVICE_TYPES } from 'matrix-js-sdk';
|
||||
|
||||
import MatrixClientPeg from './MatrixClientPeg';
|
||||
import Modal from './Modal';
|
||||
import sdk from './index';
|
||||
import { _t } from './languageHandler';
|
||||
import { Service, startTermsFlow, TermsNotSignedError } from './Terms';
|
||||
import {
|
||||
doesAccountDataHaveIdentityServer,
|
||||
doesIdentityServerHaveTerms,
|
||||
useDefaultIdentityServer,
|
||||
} from './utils/IdentityServerUtils';
|
||||
import { abbreviateUrl } from './utils/UrlUtils';
|
||||
|
||||
export class AbortedIdentityActionError extends Error {}
|
||||
|
||||
export default class IdentityAuthClient {
|
||||
/**
|
||||
|
@ -89,7 +100,10 @@ export default class IdentityAuthClient {
|
|||
try {
|
||||
await this._checkToken(token);
|
||||
} catch (e) {
|
||||
if (e instanceof TermsNotSignedError) {
|
||||
if (
|
||||
e instanceof TermsNotSignedError ||
|
||||
e instanceof AbortedIdentityActionError
|
||||
) {
|
||||
// Retrying won't help this
|
||||
throw e;
|
||||
}
|
||||
|
@ -106,6 +120,8 @@ export default class IdentityAuthClient {
|
|||
}
|
||||
|
||||
async _checkToken(token) {
|
||||
const identityServerUrl = this._matrixClient.getIdentityServerUrl();
|
||||
|
||||
try {
|
||||
await this._matrixClient.getIdentityAccount(token);
|
||||
} catch (e) {
|
||||
|
@ -113,7 +129,7 @@ export default class IdentityAuthClient {
|
|||
console.log("Identity Server requires new terms to be agreed to");
|
||||
await startTermsFlow([new Service(
|
||||
SERVICE_TYPES.IS,
|
||||
this._matrixClient.getIdentityServerUrl(),
|
||||
identityServerUrl,
|
||||
token,
|
||||
)]);
|
||||
return;
|
||||
|
@ -121,6 +137,40 @@ export default class IdentityAuthClient {
|
|||
throw e;
|
||||
}
|
||||
|
||||
if (
|
||||
!this.tempClient &&
|
||||
!doesAccountDataHaveIdentityServer() &&
|
||||
!await doesIdentityServerHaveTerms(identityServerUrl)
|
||||
) {
|
||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||
const { finished } = Modal.createTrackedDialog('Default identity server terms warning', '',
|
||||
QuestionDialog, {
|
||||
title: _t("Identity server has no terms of service"),
|
||||
description: <div>
|
||||
<p>{_t(
|
||||
"This action requires accessing the default identity server " +
|
||||
"<server /> to validate an email address or phone number, but the server " +
|
||||
"does not have any terms of service.", {},
|
||||
{
|
||||
server: () => <b>{abbreviateUrl(identityServerUrl)}</b>,
|
||||
},
|
||||
)}</p>
|
||||
<p>{_t(
|
||||
"Only continue if you trust the owner of the server.",
|
||||
)}</p>
|
||||
</div>,
|
||||
button: _t("Trust"),
|
||||
});
|
||||
const [confirmed] = await finished;
|
||||
if (confirmed) {
|
||||
useDefaultIdentityServer();
|
||||
} else {
|
||||
throw new AbortedIdentityActionError(
|
||||
"User aborted identity server action without terms",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// We should ensure the token in `localStorage` is cleared
|
||||
// appropriately. We already clear storage on sign out, but we'll need
|
||||
// additional clearing when changing ISes in settings as part of future
|
||||
|
|
|
@ -24,9 +24,8 @@ import Modal from '../../../Modal';
|
|||
import dis from "../../../dispatcher";
|
||||
import { getThreepidsWithBindStatus } from '../../../boundThreepids';
|
||||
import IdentityAuthClient from "../../../IdentityAuthClient";
|
||||
import {SERVICE_TYPES} from "matrix-js-sdk";
|
||||
import {abbreviateUrl, unabbreviateUrl} from "../../../utils/UrlUtils";
|
||||
import { getDefaultIdentityServerUrl } from '../../../utils/IdentityServerUtils';
|
||||
import { getDefaultIdentityServerUrl, doesIdentityServerHaveTerms } from '../../../utils/IdentityServerUtils';
|
||||
|
||||
// We'll wait up to this long when checking for 3PID bindings on the IS.
|
||||
const REACHABILITY_TIMEOUT = 10000; // ms
|
||||
|
@ -162,19 +161,8 @@ export default class SetIdServer extends React.Component {
|
|||
let save = true;
|
||||
|
||||
// Double check that the identity server even has terms of service.
|
||||
let terms;
|
||||
try {
|
||||
terms = await MatrixClientPeg.get().getTerms(SERVICE_TYPES.IS, fullUrl);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (e.cors === "rejected" || e.httpStatus === 404) {
|
||||
terms = null;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (!terms || !terms["policies"] || Object.keys(terms["policies"]).length <= 0) {
|
||||
const hasTerms = await doesIdentityServerHaveTerms(fullUrl);
|
||||
if (!hasTerms) {
|
||||
const [confirmed] = await this._showNoTermsWarning(fullUrl);
|
||||
save = confirmed;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,10 @@
|
|||
"Failed to invite users to %(groupId)s": "Failed to invite users to %(groupId)s",
|
||||
"Failed to add the following rooms to %(groupId)s:": "Failed to add the following rooms to %(groupId)s:",
|
||||
"Unnamed Room": "Unnamed Room",
|
||||
"Identity server has no terms of service": "Identity server has no terms of service",
|
||||
"This action requires accessing the default identity server <server /> to validate an email address or phone number, but the server does not have any terms of service.": "This action requires accessing the default identity server <server /> to validate an email address or phone number, but the server does not have any terms of service.",
|
||||
"Only continue if you trust the owner of the server.": "Only continue if you trust the owner of the server.",
|
||||
"Trust": "Trust",
|
||||
"Error": "Error",
|
||||
"Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.",
|
||||
"Dismiss": "Dismiss",
|
||||
|
@ -563,9 +567,7 @@
|
|||
"Change identity server": "Change identity server",
|
||||
"Disconnect from the identity server <current /> and connect to <new /> instead?": "Disconnect from the identity server <current /> and connect to <new /> instead?",
|
||||
"Terms of service not accepted or the identity server is invalid.": "Terms of service not accepted or the identity server is invalid.",
|
||||
"Identity server has no terms of service": "Identity server has no terms of service",
|
||||
"The identity server you have chosen does not have any terms of service.": "The identity server you have chosen does not have any terms of service.",
|
||||
"Only continue if you trust the owner of the server.": "Only continue if you trust the owner of the server.",
|
||||
"Disconnect identity server": "Disconnect identity server",
|
||||
"Disconnect from the identity server <idserver />?": "Disconnect from the identity server <idserver />?",
|
||||
"Disconnect": "Disconnect",
|
||||
|
|
|
@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { SERVICE_TYPES } from 'matrix-js-sdk';
|
||||
import SdkConfig from '../SdkConfig';
|
||||
import MatrixClientPeg from '../MatrixClientPeg';
|
||||
|
||||
|
@ -28,3 +29,24 @@ export function useDefaultIdentityServer() {
|
|||
base_url: url,
|
||||
});
|
||||
}
|
||||
|
||||
export async function doesIdentityServerHaveTerms(fullUrl) {
|
||||
let terms;
|
||||
try {
|
||||
terms = await MatrixClientPeg.get().getTerms(SERVICE_TYPES.IS, fullUrl);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (e.cors === "rejected" || e.httpStatus === 404) {
|
||||
terms = null;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return terms && terms["policies"] && (Object.keys(terms["policies"]).length > 0);
|
||||
}
|
||||
|
||||
export function doesAccountDataHaveIdentityServer() {
|
||||
const event = MatrixClientPeg.get().getAccountData("m.identity_server");
|
||||
return event && event.getContent() && event.getContent()['base_url'];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue