From e310ec0a2b757a7038bc3d90d66461167ce6b33c Mon Sep 17 00:00:00 2001 From: Tom J Date: Sat, 22 Feb 2020 19:53:05 +0000 Subject: [PATCH 1/2] issue 2517 disallow domains search --- extension/js/common/api/attester.ts | 3 +++ extension/js/common/rules.ts | 5 +++++ test/source/mock.ts | 15 ++++++++------- test/source/mock/backend/backend-data.ts | 3 +++ test/source/mock/google/google-data.ts | 7 ++++++- test/source/tests/tests/setup.ts | 13 +++++++++++++ 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/extension/js/common/api/attester.ts b/extension/js/common/api/attester.ts index 58fdab22f58..fc9a418fd33 100644 --- a/extension/js/common/api/attester.ts +++ b/extension/js/common/api/attester.ts @@ -19,6 +19,9 @@ export class Attester extends Api { } public lookupEmail = async (email: string): Promise => { + if (!this.rules.canLookupThisRecipientOnAttester(email)) { + return { pubkey: null, pgpClient: null }; // tslint:disable-line:no-null-keyword + } try { const r = await this.pubCall(`pub/${email}`); // when requested from the content script, `getResponseHeader` will be missing because it's not a real XMLHttpRequest we are getting back diff --git a/extension/js/common/rules.ts b/extension/js/common/rules.ts index 07c795466ef..9f13ab0d232 100644 --- a/extension/js/common/rules.ts +++ b/extension/js/common/rules.ts @@ -11,6 +11,7 @@ type DomainRules$flag = 'NO_PRV_CREATE' | 'NO_PRV_BACKUP' | export type DomainRules = { flags: DomainRules$flag[], custom_keyserver_url?: string, + disallow_attester_search_for_domains?: string[], }; export class Rules { @@ -56,4 +57,8 @@ export class Rules { return !this.domainRules.flags.includes('NO_ATTESTER_SUBMIT'); } + public canLookupThisRecipientOnAttester = (emailAddr: string) => { + return !(this.domainRules.disallow_attester_search_for_domains || []).includes(emailAddr.split('@')[1] || 'NONE'); + } + } diff --git a/test/source/mock.ts b/test/source/mock.ts index e12408a2e5b..634fbde9485 100644 --- a/test/source/mock.ts +++ b/test/source/mock.ts @@ -8,14 +8,15 @@ import { Config } from './util'; import { opgp } from './core/pgp'; import { startAllApisMock } from './mock/all-apis-mock'; +export const acctsWithoutMockData = [ + 'flowcrypt.test.key.multibackup@gmail.com', + 'has.pub@org-rules-test.flowcrypt.com', + 'no.pub@org-rules-test.flowcrypt.com', + 'user@no-submit-org-rule.flowcrypt.com', + 'user@no-search-domains-org-rule.flowcrypt.com', +]; + export const mock = async (logger: (line: string) => void) => { - const acctsWithoutMockData = [ - 'flowcrypt.test.key.multibackup@gmail.com', - 'has.pub@org-rules-test.flowcrypt.com', - 'no.pub@org-rules-test.flowcrypt.com', - 'user@no-submit-org-rule.flowcrypt.com', - 'user@no-search-domains-org-rule.flowcrypt.com', - ]; const start = Date.now(); await Promise.all(Config.secrets.auth.google.map(a => a.email).map(async email => { // load and decrypt mock data if missing if (acctsWithoutMockData.includes(email)) { diff --git a/test/source/mock/backend/backend-data.ts b/test/source/mock/backend/backend-data.ts index bff94a4339e..f09de9adca7 100644 --- a/test/source/mock/backend/backend-data.ts +++ b/test/source/mock/backend/backend-data.ts @@ -56,6 +56,9 @@ export class BackendData { if (domain === 'no-submit-org-rule.flowcrypt.com') { return { "flags": ["NO_ATTESTER_SUBMIT"] }; } + if (domain === 'no-search-domains-org-rule.flowcrypt.com') { + return { "flags": [], "disallow_attester_search_for_domains": ["flowcrypt.com"] }; + } return { 'flags': [] }; } diff --git a/test/source/mock/google/google-data.ts b/test/source/mock/google/google-data.ts index b116227b2ef..e2a4c5dad4d 100644 --- a/test/source/mock/google/google-data.ts +++ b/test/source/mock/google/google-data.ts @@ -5,6 +5,7 @@ import { AddressObject, ParsedMail, StructuredHeader } from 'mailparser'; import UserMessages from '../../../samples/mock-data'; import { Util } from '../../util/index'; import { readFileSync } from 'fs'; +import { acctsWithoutMockData } from '../../mock'; type GmailMsg$header = { name: string, value: string }; type GmailMsg$payload$body = { attachmentId?: string, size: number, data?: string }; @@ -106,7 +107,11 @@ export class GoogleData { constructor(private acct: string) { if (!DATA[acct]) { - DATA[acct] = JSON.parse(readFileSync(`./test/samples/${acct.replace(/[^a-z0-9]+/g, '')}.json`, { encoding: 'UTF-8' })) as AcctDataFile; + if (acctsWithoutMockData.includes(acct)) { + DATA[acct] = { drafts: [], messages: [], attachments: {}, labels: [] }; + } else { + DATA[acct] = JSON.parse(readFileSync(`./test/samples/${acct.replace(/[^a-z0-9]+/g, '')}.json`, { encoding: 'UTF-8' })) as AcctDataFile; + } if (UserMessages[acct]) { DATA[acct].drafts = UserMessages[acct].drafts; DATA[acct].messages.push(...UserMessages[acct].messages); diff --git a/test/source/tests/tests/setup.ts b/test/source/tests/tests/setup.ts index 444af4e9a4a..e8f40198770 100644 --- a/test/source/tests/tests/setup.ts +++ b/test/source/tests/tests/setup.ts @@ -9,6 +9,7 @@ import { SetupPageRecipe } from '../page-recipe/setup-page-recipe'; import { TestWithBrowser } from '../../test'; import { expect } from 'chai'; import { SettingsPageRecipe } from '../page-recipe/settings-page-recipe'; +import { ComposePageRecipe } from '../page-recipe/compose-page-recipe'; // tslint:disable:no-blank-lines-func @@ -158,6 +159,18 @@ export const defineSetupTests = (testVariant: TestVariant, testWithBrowser: Test await attesterFrame.waitAndRespondToModal('error', 'confirm', 'Disallowed by your organisation rules'); })); + ava.default('user@no-search-domains-org-rule.flowcrypt.com - do not search attester for recipients on particular domains', testWithBrowser(undefined, async (t, browser) => { + // disallowed searching attester for pubkeys on "flowcrypt.com" domain + // below we search for human@flowcrypt.com which normally has pubkey on attester, but none should be found due to the rule + const acct = 'user@no-search-domains-org-rule.flowcrypt.com'; + const settingsPage = await BrowserRecipe.openSettingsLoginApprove(t, browser, acct); + await SetupPageRecipe.manualEnter(settingsPage, 'flowcrypt.test.key.used.pgp'); + const composePage = await ComposePageRecipe.openStandalone(t, browser, acct); + await ComposePageRecipe.fillMsg(composePage, { to: 'human@flowcrypt.com' }, 'normally has pubkey but should show none'); + await composePage.waitForContent('.email_address.no_pgp', 'human@flowcrypt.com'); + await composePage.waitAll('@input-password'); + })); + } }; From 5dc96a377b552a537764371442855a8ef44b9dea Mon Sep 17 00:00:00 2001 From: Tom J Date: Sat, 22 Feb 2020 19:55:27 +0000 Subject: [PATCH 2/2] added console info --- extension/js/common/api/attester.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extension/js/common/api/attester.ts b/extension/js/common/api/attester.ts index fc9a418fd33..d17ec95b581 100644 --- a/extension/js/common/api/attester.ts +++ b/extension/js/common/api/attester.ts @@ -20,6 +20,7 @@ export class Attester extends Api { public lookupEmail = async (email: string): Promise => { if (!this.rules.canLookupThisRecipientOnAttester(email)) { + console.info(`Skipping attester lookup of ${email} because attester search on this domain is disabled.`); return { pubkey: null, pgpClient: null }; // tslint:disable-line:no-null-keyword } try {