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:
J. Ryan Stinnett 2019-10-31 11:58:31 +00:00
parent 54cea6a5e3
commit 0fc5108817
4 changed files with 81 additions and 19 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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",

View file

@ -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'];
}