Skip to content

Commit

Permalink
Merge branch 'develop' into t3chguy/wat/230.1
Browse files Browse the repository at this point in the history
  • Loading branch information
t3chguy authored Sep 24, 2024
2 parents 7feb5a0 + a1bdcee commit 3620c5a
Show file tree
Hide file tree
Showing 32 changed files with 904 additions and 250 deletions.
2 changes: 0 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,6 @@ module.exports = {
"!matrix-js-sdk/src/crypto/aes",
"!matrix-js-sdk/src/crypto/keybackup",
"!matrix-js-sdk/src/crypto/deviceinfo",
"!matrix-js-sdk/src/crypto/key_passphrase",
"!matrix-js-sdk/src/crypto/recoverykey",
"!matrix-js-sdk/src/crypto/dehydration",
"!matrix-js-sdk/src/oidc",
"!matrix-js-sdk/src/oidc/discovery",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/notify-element-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
name: "Notify Element Web"
runs-on: ubuntu-latest
# Only respect triggers from our develop branch, ignore that of forks
if: github.repository == 'matrix-org/matrix-react-sdk'
if: github.repository == 'element-hq/matrix-react-sdk'
steps:
- name: Notify element-web repo that a new SDK build is on develop
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/playwright-image-updates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@4320041ed380b20e97d388d56a7fb4f9b8c20e79 # v7
uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
branch: actions/playwright-image-updates
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ concurrency: ${{ github.workflow }}
jobs:
release:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop
secrets: inherit
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
with:
final: ${{ inputs.mode == 'final' }}
npm: ${{ inputs.npm }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
with:
repository: ${{ inputs.matrix-js-sdk-sha && 'matrix-org/matrix-react-sdk' || github.repository }}
repository: ${{ inputs.matrix-js-sdk-sha && 'element-hq/matrix-react-sdk' || github.repository }}

- name: Yarn cache
uses: actions/setup-node@v4
Expand Down Expand Up @@ -96,7 +96,7 @@ jobs:
needs: jest
steps:
- name: Skip SonarCloud
uses: Sibz/github-status-action@071b5370da85afbb16637d6eed8524a06bc2053e # v1
uses: Sibz/github-status-action@faaa4d96fecf273bd762985e0e7f9f933c774918 # v1
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: success
Expand All @@ -111,7 +111,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
repository: ${{ inputs.matrix-js-sdk-sha && 'matrix-org/matrix-react-sdk' || github.repository }}
repository: ${{ inputs.matrix-js-sdk-sha && 'element-hq/matrix-react-sdk' || github.repository }}

- uses: actions/setup-node@v4
with:
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
},
"resolutions": {
"@types/react-dom": "17.0.25",
"@types/react": "17.0.80",
"@types/react": "17.0.82",
"@types/seedrandom": "3.0.8",
"oidc-client-ts": "3.0.1",
"jwt-decode": "4.0.0",
Expand Down Expand Up @@ -91,7 +91,7 @@
"classnames": "^2.2.6",
"commonmark": "^0.31.0",
"counterpart": "^0.18.6",
"css-tree": "^2.3.1",
"css-tree": "^3.0.0",
"diff-dom": "^5.0.0",
"diff-match-patch": "^1.0.5",
"emojibase-regex": "15.3.2",
Expand Down Expand Up @@ -183,7 +183,7 @@
"@types/node-fetch": "^2.6.2",
"@types/pako": "^2.0.0",
"@types/qrcode": "^1.3.5",
"@types/react": "17.0.80",
"@types/react": "17.0.82",
"@types/react-beautiful-dnd": "^13.0.0",
"@types/react-dom": "17.0.25",
"@types/react-transition-group": "^4.4.0",
Expand All @@ -198,7 +198,7 @@
"axe-core": "4.10.0",
"babel-jest": "^29.0.0",
"blob-polyfill": "^9.0.0",
"eslint": "8.57.0",
"eslint": "8.57.1",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-deprecate": "0.8.5",
Expand Down
89 changes: 45 additions & 44 deletions playwright/pages/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type { Logger } from "matrix-js-sdk/src/logger";
import type { SecretStorageKeyDescription } from "matrix-js-sdk/src/secret-storage";
import type { Credentials, HomeserverInstance } from "../plugins/homeserver";
import type { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api";
import { Client } from "./client";
import { bootstrapCrossSigningForClient, Client } from "./client";

export interface CreateBotOpts {
/**
Expand Down Expand Up @@ -90,9 +90,13 @@ export class Bot extends Client {
}

protected async getClientHandle(): Promise<JSHandle<ExtendedMatrixClient>> {
if (this.handlePromise) return this.handlePromise;
if (!this.handlePromise) this.handlePromise = this.buildClient();
return this.handlePromise;
}

this.handlePromise = this.page.evaluateHandle(
private async buildClient(): Promise<JSHandle<ExtendedMatrixClient>> {
const credentials = await this.getCredentials();
const clientHandle = await this.page.evaluateHandle(
async ({ homeserver, credentials, opts }) => {
function getLogger(loggerName: string): Logger {
const logger = {
Expand Down Expand Up @@ -172,53 +176,50 @@ export class Bot extends Client {
});
}

if (!opts.startClient) {
return cli;
}

await cli.initRustCrypto({ useIndexedDB: false });
cli.setGlobalErrorOnUnknownDevices(false);
await cli.startClient();

if (opts.bootstrapCrossSigning) {
// XXX: workaround https://github.com/element-hq/element-web/issues/26755
// wait for out device list to be available, as a proxy for the device keys having been uploaded.
await cli.getCrypto()!.getUserDeviceInfo([credentials.userId]);

await cli.getCrypto()!.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (func) => {
await func({
type: "m.login.password",
identifier: {
type: "m.id.user",
user: credentials.userId,
},
password: credentials.password,
});
},
});
}

if (opts.bootstrapSecretStorage) {
const passphrase = "new passphrase";
const recoveryKey = await cli.getCrypto().createRecoveryKeyFromPassphrase(passphrase);
Object.assign(cli, { __playwright_recovery_key: recoveryKey });

await cli.getCrypto()!.bootstrapSecretStorage({
setupNewSecretStorage: true,
setupNewKeyBackup: true,
createSecretStorageKey: () => Promise.resolve(recoveryKey),
});
}

return cli;
},
{
homeserver: this.homeserver.config,
credentials: await this.getCredentials(),
credentials,
opts: this.opts,
},
);
return this.handlePromise;

// If we weren't configured to start the client, bail out now.
if (!this.opts.startClient) {
return clientHandle;
}

await clientHandle.evaluate(async (cli) => {
await cli.initRustCrypto({ useIndexedDB: false });
cli.setGlobalErrorOnUnknownDevices(false);
await cli.startClient();
});

if (this.opts.bootstrapCrossSigning) {
// XXX: workaround https://github.com/element-hq/element-web/issues/26755
// wait for out device list to be available, as a proxy for the device keys having been uploaded.
await clientHandle.evaluate(async (cli, credentials) => {
await cli.getCrypto()!.getUserDeviceInfo([credentials.userId]);
}, credentials);

await bootstrapCrossSigningForClient(clientHandle, credentials);
}

if (this.opts.bootstrapSecretStorage) {
await clientHandle.evaluate(async (cli) => {
const passphrase = "new passphrase";
const recoveryKey = await cli.getCrypto().createRecoveryKeyFromPassphrase(passphrase);
Object.assign(cli, { __playwright_recovery_key: recoveryKey });

await cli.getCrypto()!.bootstrapSecretStorage({
setupNewSecretStorage: true,
setupNewKeyBackup: true,
createSecretStorageKey: () => Promise.resolve(recoveryKey),
});
});
}

return clientHandle;
}
}
45 changes: 30 additions & 15 deletions playwright/pages/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,24 +356,11 @@ export class Client {
}

/**
* Boostraps cross-signing.
* Bootstraps cross-signing.
*/
public async bootstrapCrossSigning(credentials: Credentials): Promise<void> {
const client = await this.prepareClient();
return client.evaluate(async (client, credentials) => {
await client.getCrypto().bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (func) => {
await func({
type: "m.login.password",
identifier: {
type: "m.id.user",
user: credentials.userId,
},
password: credentials.password,
});
},
});
}, credentials);
return bootstrapCrossSigningForClient(client, credentials);
}

/**
Expand Down Expand Up @@ -439,3 +426,31 @@ export class Client {
);
}
}

/** Call `CryptoApi.bootstrapCrossSigning` on the given Matrix client, using the given credentials to authenticate
* the UIA request.
*/
export function bootstrapCrossSigningForClient(
client: JSHandle<MatrixClient>,
credentials: Credentials,
resetKeys: boolean = false,
) {
return client.evaluate(
async (client, { credentials, resetKeys }) => {
await client.getCrypto().bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (func) => {
await func({
type: "m.login.password",
identifier: {
type: "m.id.user",
user: credentials.userId,
},
password: credentials.password,
});
},
setupNewCrossSigning: resetKeys,
});
},
{ credentials, resetKeys },
);
}
5 changes: 2 additions & 3 deletions src/SecurityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/

import { ICryptoCallbacks, SecretStorage } from "matrix-js-sdk/src/matrix";
import { deriveKey } from "matrix-js-sdk/src/crypto/key_passphrase";
import { decodeRecoveryKey } from "matrix-js-sdk/src/crypto/recoverykey";
import { deriveRecoveryKeyFromPassphrase, decodeRecoveryKey } from "matrix-js-sdk/src/crypto-api";
import { logger } from "matrix-js-sdk/src/logger";

import type CreateSecretStorageDialog from "./async-components/views/dialogs/security/CreateSecretStorageDialog";
Expand Down Expand Up @@ -64,7 +63,7 @@ function makeInputToKey(
): (keyParams: KeyParams) => Promise<Uint8Array> {
return async ({ passphrase, recoveryKey }): Promise<Uint8Array> => {
if (passphrase) {
return deriveKey(passphrase, keyInfo.passphrase.salt, keyInfo.passphrase.iterations);
return deriveRecoveryKeyFromPassphrase(passphrase, keyInfo.passphrase.salt, keyInfo.passphrase.iterations);
} else if (recoveryKey) {
return decodeRecoveryKey(recoveryKey);
}
Expand Down
14 changes: 8 additions & 6 deletions src/components/structures/MatrixChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -952,18 +952,20 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}

private async startRegistration(params: { [key: string]: string }, isMobileRegistration?: boolean): Promise<void> {
if (!SettingsStore.getValue(UIFeature.Registration)) {
// If registration is disabled or mobile registration is requested but not enabled in settings redirect to the welcome screen
if (
!SettingsStore.getValue(UIFeature.Registration) ||
(isMobileRegistration && !SettingsStore.getValue("Registration.mobileRegistrationHelper"))
) {
this.showScreen("welcome");
return;
}
const isMobileRegistrationAllowed =
isMobileRegistration && SettingsStore.getValue("Registration.mobileRegistrationHelper");

const newState: Partial<IState> = {
view: Views.REGISTER,
};

if (isMobileRegistrationAllowed && params.hs_url) {
if (isMobileRegistration && params.hs_url) {
try {
const config = await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(params.hs_url);
newState.serverConfig = config;
Expand Down Expand Up @@ -992,12 +994,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
newState.register_id_sid = params.sid;
}

newState.isMobileRegistration = isMobileRegistrationAllowed;
newState.isMobileRegistration = isMobileRegistration;

this.setStateForNewView(newState);
ThemeController.isLogin = true;
this.themeWatcher.recheck();
this.notifyNewScreen(isMobileRegistrationAllowed ? "mobile_register" : "register");
this.notifyNewScreen(isMobileRegistration ? "mobile_register" : "register");
}

// switch view to the given room
Expand Down
2 changes: 1 addition & 1 deletion src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1364,7 +1364,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
if (containsEmoji(ev.getContent(), effect.emojis) || ev.getContent().msgtype === effect.msgType) {
// For initial threads launch, chat effects are disabled see #19731
if (!ev.isRelation(THREAD_RELATION_TYPE.name)) {
dis.dispatch({ action: `effects.${effect.command}` });
dis.dispatch({ action: `effects.${effect.command}`, event: ev });
}
}
});
Expand Down
7 changes: 6 additions & 1 deletion src/components/structures/auth/Registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ export default class Registration extends React.Component<IProps, IState> {
serverConfig={this.props.serverConfig}
canSubmit={!this.state.serverErrorIsFatal}
matrixClient={this.state.matrixClient}
mobileRegister={this.props.mobileRegister}
/>
</React.Fragment>
);
Expand Down Expand Up @@ -779,7 +780,11 @@ export default class Registration extends React.Component<IProps, IState> {
);
}
if (this.props.mobileRegister) {
return <div className="mx_MobileRegister_body">{body}</div>;
return (
<div className="mx_MobileRegister_body" data-testid="mobile-register">
{body}
</div>
);
}
return (
<AuthPage>
Expand Down
13 changes: 13 additions & 0 deletions src/components/views/auth/CaptchaForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ export default class CaptchaForm extends React.Component<ICaptchaFormProps, ICap

public componentWillUnmount(): void {
this.resetRecaptcha();
// Resettting the captcha does not clear the challenge overlay from the body in android webviews.
// Search for an iframe with the challenge src and remove it's topmost ancestor from the body.
// TODO: Remove this when the "mobile_register" page is retired.
const iframes = document.querySelectorAll("iframe");
for (const iframe of iframes) {
if (iframe.src.includes("https://www.recaptcha.net/recaptcha/api2/bframe")) {
let parentBeforeBody: HTMLElement | null = iframe;
do {
parentBeforeBody = parentBeforeBody.parentElement;
} while (parentBeforeBody?.parentElement && parentBeforeBody.parentElement != document.body);
parentBeforeBody?.remove();
}
}
}

// Borrowed directly from: https://github.com/codeep/react-recaptcha-google/commit/e118fa5670fa268426969323b2e7fe77698376ba
Expand Down
Loading

0 comments on commit 3620c5a

Please sign in to comment.