Skip to content

Commit

Permalink
Merge branch 'master' into 5498-puppeteer-v21
Browse files Browse the repository at this point in the history
# Conflicts:
#	package-lock.json
#	package.json
  • Loading branch information
sosnovsky committed May 14, 2024
2 parents 4486624 + e9c7694 commit 149bfaf
Show file tree
Hide file tree
Showing 55 changed files with 56,992 additions and 29,518 deletions.
4 changes: 2 additions & 2 deletions extension/chrome/dev/ci_unit_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import { ContactStore } from '../../js/common/platform/store/contact-store.js';
import { Debug } from '../../js/common/platform/debug.js';
import { Catch } from '../../js/common/platform/catch.js';
import { Url } from '../../js/common/core/common.js';
import * as forge from 'node-forge';
import { Gmail } from '../../js/common/api/email-provider/gmail/gmail.js';
import { PgpHash } from '../../js/common/core/crypto/pgp/pgp-hash.js';
import { PgpArmor } from '../../js/common/core/crypto/pgp/pgp-armor.js';
import { Xss } from '../../js/common/platform/xss.js';
import { ExpirationCache } from '../../js/common/core/expiration-cache.js';

/**
* importing all libs that are tested in ci tests
Expand All @@ -32,6 +32,7 @@ const libs: unknown[] = [
Attachment,
AttachmentUI,
Buf,
ExpirationCache,
KeyUtil,
Mime,
Wkd,
Expand All @@ -53,5 +54,4 @@ const libs: unknown[] = [
for (const lib of libs) {
(window as any)[(lib as any).name] = lib;
}
(window as any).forge = forge;
/* eslint-enable @typescript-eslint/no-explicit-any */
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ export class ComposeRecipientsModule extends ViewModule<ComposeView> {
};

private inputsDragEnterHandler = (target: HTMLElement) => {
if (Catch.browser().name === 'firefox') {
if (Catch.isFirefox()) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.insertCursorBefore(target.previousElementSibling!, true);
} else {
Expand All @@ -485,15 +485,15 @@ export class ComposeRecipientsModule extends ViewModule<ComposeView> {
};

private inputsDragLeaveHandler = (target: HTMLElement) => {
if (Catch.browser().name === 'firefox') {
if (Catch.isFirefox()) {
this.removeCursor(target.previousElementSibling as HTMLElement);
} else {
target.blur();
}
};

private inputsDropHandler = (target: HTMLElement) => {
if (Catch.browser().name === 'firefox') {
if (Catch.isFirefox()) {
this.removeCursor(target.previousElementSibling as HTMLElement);
}
if (this.dragged) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class ComposeSendBtnPopoverModule extends ViewModule<ComposeView> {
this.choices.richtext = await this.richTextUserChoiceRetrieve();
for (const key of Object.keys(popoverItems)) {
const popoverOpt = key as PopoverOpt;
if (popoverOpt === 'richtext' && !this.view.debug && Catch.browser().name !== 'firefox') {
if (popoverOpt === 'richtext' && !this.view.debug && !Catch.isFirefox()) {
continue; // richtext not deployed to Chrome yet, for now only allow firefox (and also in automated tests which set debug===true)
}
const item = popoverItems[popoverOpt];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class ComposeSizeModule extends ViewModule<ComposeView> {
* @param updateRefBodyHeight - set to true to take a new snapshot of intended html body height
*/
public setInputTextHeightManuallyIfNeeded = (updateRefBodyHeight = false) => {
if (!this.view.isReplyBox && Catch.browser().name === 'firefox') {
if (!this.view.isReplyBox && Catch.isFirefox()) {
this.view.S.cached('input_text').css('height', '0');
let cellHeightExceptText = 0;
for (const cell of this.view.S.cached('all_cells_except_text')) {
Expand Down
2 changes: 1 addition & 1 deletion extension/chrome/elements/compose.htm
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ <h1 id="header_title" data-test="header-title">New Secure Message</h1>
<a href="https://flowcrypt.com/docs/getting-started/send-and-receive/send/send-password-protected-emails.html" target="_blank"
>password-protected</a
>:
<input id="input_password" autocomplete="off" placeholder="email password" tabindex="5" data-test="input-password" maxlength="256" />
<input id="input_password" autocomplete="off" placeholder="message password" tabindex="5" data-test="input-password" maxlength="256" />
</div>
<div class="warning_no_pubkey_on_attester">
<span data-test="container-no-pubkey-on-attester">
Expand Down
2 changes: 1 addition & 1 deletion extension/chrome/popups/select_account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ View.run(
})
);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
$('html, body').css('height', $('.content').height()! + (Catch.browser().name === 'firefox' ? 40 : 0)); // .content is in template
$('html, body').css('height', $('.content').height()! + (Catch.isFirefox() ? 40 : 0)); // .content is in template
};

public setHandlers = () => {
Expand Down
21 changes: 0 additions & 21 deletions extension/js/background_page/background_page.htm

This file was deleted.

22 changes: 19 additions & 3 deletions extension/js/common/api/authentication/google/google-oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { FLAVOR, GOOGLE_OAUTH_SCREEN_HOST, OAUTH_GOOGLE_API_HOST } from '../../.
import { ApiErr } from '../../shared/api-error.js';
import { Ajax, Api } from '../../shared/api.js';

import { Bm, GoogleAuthWindowResult$result } from '../../../browser/browser-msg.js';
import { Bm, GoogleAuthWindowResult$result, ScreenDimensions } from '../../../browser/browser-msg.js';
import { InMemoryStoreKeys } from '../../../core/const.js';
import { OAuth2 } from '../../../oauth2/oauth2.js';
import { Catch } from '../../../platform/catch.js';
Expand All @@ -18,6 +18,7 @@ import { OAuth } from '../generic/oauth.js';
import { ExternalService } from '../../account-servers/external-service.js';
import { GoogleAuthErr } from '../../shared/api-error.js';
import { Assert, AssertError } from '../../../assert.js';
import { Ui } from '../../../browser/ui.js';

/* eslint-disable @typescript-eslint/naming-convention */
type GoogleAuthTokensResponse = {
Expand Down Expand Up @@ -148,7 +149,17 @@ export class GoogleOAuth extends OAuth {
}
}

public static async newAuthPopup({ acctEmail, scopes, save }: { acctEmail?: string; scopes?: string[]; save?: boolean }): Promise<AuthRes> {
public static async newAuthPopup({
acctEmail,
scopes,
save,
screenDimensions,
}: {
acctEmail?: string;
scopes?: string[];
save?: boolean;
screenDimensions?: ScreenDimensions;
}): Promise<AuthRes> {
if (acctEmail) {
acctEmail = acctEmail.toLowerCase();
}
Expand All @@ -161,7 +172,12 @@ export class GoogleOAuth extends OAuth {
}
const authRequest = GoogleOAuth.newAuthRequest(acctEmail, scopes);
const authUrl = GoogleOAuth.apiGoogleAuthCodeUrl(authRequest);
const authWindowResult = await OAuth2.webAuthFlow(authUrl);
// Added below logic because in service worker, it's not possible to access window object.
// Therefore need to retrieve screenDimensions when calling service worker and pass it to OAuth2
if (!screenDimensions) {
screenDimensions = Ui.getScreenDimensions();
}
const authWindowResult = await OAuth2.webAuthFlow(authUrl, screenDimensions);
const authRes = await GoogleOAuth.getAuthRes({
acctEmail,
save,
Expand Down
73 changes: 30 additions & 43 deletions extension/js/common/api/email-provider/gmail/gmail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ import { Dict, Str, Value } from '../../../core/common.js';
import { EmailProviderApi, EmailProviderInterface, Backups } from '../email-provider-api.js';
import { GMAIL_GOOGLE_API_HOST, gmailBackupSearchQuery } from '../../../core/const.js';
import { GmailParser, GmailRes } from './gmail-parser.js';
import { AjaxErr } from '../../shared/api-error.js';
import { Attachment } from '../../../core/attachment.js';
import { BrowserMsg } from '../../../browser/browser-msg.js';
import { Buf } from '../../../core/buf.js';
import { Catch } from '../../../platform/catch.js';
import { KeyUtil } from '../../../core/crypto/key.js';
import { Env } from '../../../browser/env.js';
import { Google } from './google.js';
import { GoogleOAuth } from '../../authentication/google/google-oauth.js';
import { SendableMsg } from '../sendable-msg.js';
import { KeyStore } from '../../../platform/store/key-store.js';
import { AjaxErr } from '../../shared/api-error.js';

export type GmailResponseFormat = 'raw' | 'full' | 'metadata';

Expand Down Expand Up @@ -167,8 +166,8 @@ export class Gmail extends EmailProviderApi implements EmailProviderInterface {
});
return chunk;
}
const stack = Catch.stackTrace();
const minBytes = 1000;
let totalBytes = 0;
const minBytes = 1000; // Define minBytes as per your requirement
let processed = 0;
return await new Promise((resolve, reject) => {
const processChunkAndResolve = (chunk: string) => {
Expand Down Expand Up @@ -207,47 +206,35 @@ export class Gmail extends EmailProviderApi implements EmailProviderInterface {
}
};
GoogleOAuth.googleApiAuthHeader(this.acctEmail)
.then(authToken => {
const r = new XMLHttpRequest();
const method = 'GET';
.then(async authToken => {
const url = `${GMAIL_GOOGLE_API_HOST}/gmail/v1/users/me/messages/${msgId}/attachments/${attachmentId}`;
r.open(method, url, true);
r.setRequestHeader('Authorization', authToken);
r.send();
let status: number;
const responsePollInterval = Catch.setHandledInterval(() => {
if (status >= 200 && status <= 299 && (r.responseText.length >= minBytes || treatAs === 'publicKey')) {
window.clearInterval(responsePollInterval);
processChunkAndResolve(r.responseText);
r.abort();
}
}, 10);
r.onreadystatechange = () => {
if (r.readyState === 2 || r.readyState === 3) {
// headers, loading
status = r.status;
if (status >= 300) {
reject(AjaxErr.fromXhr({ status, readyState: r.readyState }, { method, url, stack }));
window.clearInterval(responsePollInterval);
r.abort();
}
const response: Response = await fetch(url, {
method: 'GET',
headers: new Headers({
// eslint-disable-next-line @typescript-eslint/naming-convention
Authorization: authToken,
}),
});

if (!response.ok) throw AjaxErr.fromFetchResponse(response);
if (!response.body) throw AjaxErr.fromNetErr('No response body!');
const reader: ReadableStreamDefaultReader<Uint8Array> = response.body.getReader();
let completeChunk = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = new TextDecoder().decode(value);
totalBytes += value.length; // Update total bytes based on the Uint8Array length
completeChunk += chunk;
if (totalBytes >= minBytes || treatAs === 'publicKey') {
// Process and return the chunk if the conditions are met
return processChunkAndResolve(completeChunk); // Make sure this method returns Buf
}
if (r.readyState === 3 || r.readyState === 4) {
// loading, done
if (status >= 200 && status <= 299 && (r.responseText.length >= minBytes || treatAs === 'publicKey')) {
// done as a success - resolve in case response_poll didn't catch this yet
processChunkAndResolve(r.responseText);
window.clearInterval(responsePollInterval);
if (r.readyState === 3) {
r.abort();
}
} else {
// done as a fail - reject
reject(AjaxErr.fromXhr({ status, readyState: r.readyState }, { method, url, stack }));
window.clearInterval(responsePollInterval);
}
}
};
}

// If the loop completes without returning, it means the conditions were never met.
// Depending on your needs, you might throw an error or handle this scenario differently.
throw new Error('Failed to meet the minimum byte requirement or condition.');
})
.catch(reject);
});
Expand Down
14 changes: 14 additions & 0 deletions extension/js/common/api/shared/api-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ export class AjaxErr extends ApiCallErr {
return new AjaxErr(message, stack ?? 'no stack trace available', 0, Catch.censoredUrl(url), '', '(no status text)', undefined, undefined);
};

public static fromFetchResponse = (fetchRes: Response, stack?: string) => {
const message = `${fetchRes.statusText}: ${fetchRes.status} when ${ApiCallErr.describeApiAction(fetchRes)}`;
return new AjaxErr(
message,
stack ?? 'no stack trace available',
fetchRes.status,
Catch.censoredUrl(fetchRes.url),
'',
fetchRes.statusText,
undefined,
undefined
);
};

// no static props, else will get serialised into err reports. Static methods ok
public static fromXhr = (xhr: RawAjaxErr, req: { url: string; stack: string; method?: string; data?: unknown }) => {
const responseText = xhr.responseText || '';
Expand Down
5 changes: 4 additions & 1 deletion extension/js/common/api/shared/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,10 @@ export class Api {

public static async isInternetAccessible() {
try {
await Api.download('https://google.com');
await fetch('https://google.com', {
method: 'GET',
mode: 'no-cors',
});
return true;
} catch (e) {
if (ApiErr.isNetErr(e)) {
Expand Down
Loading

0 comments on commit 149bfaf

Please sign in to comment.