Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1254 Send password-protected messages #1308

Merged
merged 21 commits into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions Core/source/core/pgp-msg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { Catch } from '../platform/catch';
import { FcAttLinkData } from './att';
import { MsgBlockParser } from './msg-block-parser';
import { PgpArmor } from './pgp-armor';
import { PgpHash } from './pgp-hash';
import { Store } from '../platform/store';
import { openpgp } from './pgp';

Expand Down Expand Up @@ -222,8 +221,8 @@ export class PgpMsg {

public static encrypt: PgpMsgMethod.Encrypt = async ({ pubkeys, signingPrv, pwd, data, filename, armor, date }) => {
const message = openpgp.message.fromBinary(data, filename, date);

const options: OpenPGP.EncryptOptions = { armor, message, date };
let usedChallenge = false;
if (pubkeys) {
options.publicKeys = [];
for (const armoredPubkey of pubkeys) {
Expand All @@ -232,10 +231,9 @@ export class PgpMsg {
}
}
if (pwd) {
options.passwords = [await PgpHash.challengeAnswer(pwd)];
usedChallenge = true;
options.passwords = [pwd];
}
if (!pubkeys && !usedChallenge) {
if (!pubkeys && !pwd) {
throw new Error('no-pubkeys-no-challenge');
}
if (signingPrv && typeof signingPrv.isPrivate !== 'undefined' && signingPrv.isPrivate()) { // tslint:disable-line:no-unbound-method - only testing if exists
Expand Down
16 changes: 8 additions & 8 deletions Core/source/mobile-interface/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ export class Endpoints {
return fmtRes({ app_version: VERSION });
}

public encryptMsg = async (uncheckedReq: any, data: Buffers): Promise<EndpointRes> => {
const req = ValidateInput.encryptMsg(uncheckedReq);
const encrypted = await PgpMsg.encrypt({ pubkeys: req.pubKeys, data: Buf.concat(data), armor: true }) as OpenPGP.EncryptArmorResult;
return fmtRes({}, Buf.fromUtfStr(encrypted.data));
}

public generateKey = async (uncheckedReq: any): Promise<EndpointRes> => {
Store.keyCacheWipe(); // generateKey may be used when changing major settings, wipe cache to prevent dated results
const { passphrase, userIds, variant } = ValidateInput.generateKey(uncheckedReq);
Expand All @@ -57,13 +51,14 @@ export class Endpoints {
}
if (req.format === 'plain') {
const atts = (req.atts || []).map(({ name, type, base64 }) => new Att({ name, type, data: Buf.fromBase64Str(base64) }));
return fmtRes({}, Buf.fromUtfStr(await Mime.encode({ 'text/plain': req.text }, mimeHeaders, atts)));
return fmtRes({}, Buf.fromUtfStr(await Mime.encode({ 'text/plain': req.text, 'text/html': req.html }, mimeHeaders, atts)));
} else if (req.format === 'encrypt-inline') {
const encryptedAtts: Att[] = [];
for (const att of req.atts || []) {
const encryptedAtt = await PgpMsg.encrypt({ pubkeys: req.pubKeys, data: Buf.fromBase64Str(att.base64), filename: att.name, armor: false }) as OpenPGP.EncryptBinaryResult;
encryptedAtts.push(new Att({ name: `${att.name}.pgp`, type: 'application/pgp-encrypted', data: encryptedAtt.message.packets.write() }))
}

const signingPrv = await getSigningPrv(req);
const encrypted = await PgpMsg.encrypt({ pubkeys: req.pubKeys, signingPrv, data: Buf.fromUtfStr(req.text), armor: true }) as OpenPGP.EncryptArmorResult;
return fmtRes({}, Buf.fromUtfStr(await Mime.encode({ 'text/plain': encrypted.data }, mimeHeaders, encryptedAtts)));
Expand All @@ -72,6 +67,12 @@ export class Endpoints {
}
}

public encryptMsg = async (uncheckedReq: any, data: Buffers): Promise<EndpointRes> => {
const req = ValidateInput.encryptMsg(uncheckedReq);
const encrypted = await PgpMsg.encrypt({ pubkeys: req.pubKeys, pwd: req.msgPwd, data: Buf.concat(data), armor: true }) as OpenPGP.EncryptArmorResult;
return fmtRes({}, Buf.fromUtfStr(encrypted.data));
}

public encryptFile = async (uncheckedReq: any, data: Buffers): Promise<EndpointRes> => {
const req = ValidateInput.encryptFile(uncheckedReq);
const encrypted = await PgpMsg.encrypt({ pubkeys: req.pubKeys, data: Buf.concat(data), filename: req.name, armor: false }) as OpenPGP.EncryptBinaryResult;
Expand Down Expand Up @@ -304,4 +305,3 @@ export const getSigningPrv = async (req: NodeRequest.composeEmailEncrypted): Pro
throw new Error(`Fail to decrypt signing key`);
}
}

8 changes: 4 additions & 4 deletions Core/source/mobile-interface/validate-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ type Obj = { [k: string]: any };
export namespace NodeRequest {
type PrvKeyInfo = { private: string; longid: string, passphrase: string | undefined };
type Attachment = { name: string; type: string; base64: string };
interface composeEmailBase { text: string, to: string[], cc: string[], bcc: string[], from: string, subject: string, replyToMimeMsg: string, atts?: Attachment[] };
interface composeEmailBase { text: string, html?: string, to: string[], cc: string[], bcc: string[], from: string, subject: string, replyToMimeMsg: string, atts?: Attachment[] };
export interface composeEmailPlain extends composeEmailBase { format: 'plain' };
export interface composeEmailEncrypted extends composeEmailBase { format: 'encrypt-inline' | 'encrypt-pgpmime', pubKeys: string[], signingPrv: PrvKeyInfo | undefined };

export type generateKey = { passphrase: string, variant: 'rsa2048' | 'rsa4096' | 'curve25519', userIds: { name: string, email: string }[] };
export type composeEmail = composeEmailPlain | composeEmailEncrypted;
export type encryptMsg = { pubKeys: string[] };
export type encryptMsg = { pubKeys: string[], msgPwd?: string };
export type encryptFile = { pubKeys: string[], name: string };
export type parseDecryptMsg = { keys: PrvKeyInfo[], msgPwd?: string, isEmail?: boolean, verificationPubkeys?: string[] };
export type decryptFile = { keys: PrvKeyInfo[], msgPwd?: string };
Expand All @@ -37,14 +37,14 @@ export class ValidateInput {
}

public static encryptMsg = (v: any): NodeRequest.encryptMsg => {
if (isObj(v) && hasProp(v, 'pubKeys', 'string[]')) {
if (isObj(v) && hasProp(v, 'pubKeys', 'string[]') && hasProp(v, 'msgPwd', 'string?')) {
return v as NodeRequest.encryptMsg;
}
throw new Error('Wrong request structure for NodeRequest.encryptMsg');
}

public static composeEmail = (v: any): NodeRequest.composeEmail => {
if (!(isObj(v) && hasProp(v, 'text', 'string') && hasProp(v, 'from', 'string') && hasProp(v, 'subject', 'string') && hasProp(v, 'to', 'string[]') && hasProp(v, 'cc', 'string[]') && hasProp(v, 'bcc', 'string[]'))) {
if (!(isObj(v) && hasProp(v, 'text', 'string') && hasProp(v, 'html', 'string?') && hasProp(v, 'from', 'string') && hasProp(v, 'subject', 'string') && hasProp(v, 'to', 'string[]') && hasProp(v, 'cc', 'string[]') && hasProp(v, 'bcc', 'string[]'))) {
throw new Error('Wrong request structure for NodeRequest.composeEmail, need: text,from,subject,to,cc,bcc,atts (can use empty arr for cc/bcc, and can skip atts)');
}
if (!hasProp(v, 'atts', 'Attachment[]?')) {
Expand Down
12 changes: 12 additions & 0 deletions Core/source/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ for (const keypairName of allKeypairNames.filter(name => name != 'expired' && na
});
}

ava.default(`encryptMsg -> parseDecryptMsg (with password)`, async t => {
const content = 'hello\nwrld';
const msgPwd = '123';
const { data: encryptedMsg, json: encryptJson } = parseResponse(await endpoints.encryptMsg({ pubKeys: [], msgPwd: msgPwd }, [Buffer.from(content, 'utf8')]));
expectEmptyJson(encryptJson);
expectData(encryptedMsg, 'armoredMsg');
const { data: blocks, json: decryptJson } = parseResponse(await endpoints.parseDecryptMsg({ keys: [], msgPwd: msgPwd }, [encryptedMsg]));
expect(decryptJson).to.deep.equal({ text: content, replyType: 'encrypted' });
expectData(blocks, 'msgBlocks', [{ rendered: true, frameColor: 'green', htmlContent: content.replace(/\n/g, '<br />') }]);
t.pass();
});

ava.default('composeEmail format:plain -> parseDecryptMsg', async t => {
const content = 'hello\nwrld';
const { keys } = getKeypairs('rsa1');
Expand Down
18 changes: 9 additions & 9 deletions FlowCrypt.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
21C7DF09266C0D8F00C44800 /* EnterpriseServerApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21C7DF08266C0D8F00C44800 /* EnterpriseServerApi.swift */; };
21CE25E62650070300ADFF4B /* WkdUrlConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21CE25E52650070300ADFF4B /* WkdUrlConstructor.swift */; };
21EA3B592656611D00691848 /* ClientConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21EA3B15265647C400691848 /* ClientConfiguration.swift */; };
21F836B62652A26B00B2448C /* DataExntensions+ZBase32Encoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21F836B52652A26B00B2448C /* DataExntensions+ZBase32Encoding.swift */; };
21F836B62652A26B00B2448C /* DataExtensions+ZBase32Encoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21F836B52652A26B00B2448C /* DataExtensions+ZBase32Encoding.swift */; };
2C03CC16275BB53400887EEB /* EnterpriseServerApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C03CC15275BB53400887EEB /* EnterpriseServerApiTests.swift */; };
2C08F6BE273FA7B900EE1610 /* Version5SchemaMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C08F6BD273FA7B900EE1610 /* Version5SchemaMigration.swift */; };
2C124DB42728809100A2EFA6 /* ApiCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C124DB32728809100A2EFA6 /* ApiCall.swift */; };
Expand Down Expand Up @@ -345,7 +345,7 @@
D2CDC3CD2402CCD7002B045F /* UIImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8277952373732000E19C07 /* UIImageExtensions.swift */; };
D2CDC3CE2402CDB4002B045F /* DispatchTimeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DCABF1508B0C08DEDE2059 /* DispatchTimeExtensions.swift */; };
D2CDC3D32402D4FE002B045F /* DataExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DCAEFF16F5D91A35791730 /* DataExtensions.swift */; };
D2CDC3D42402D50A002B045F /* CodableExntensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DCA38E87F2B7196E0E1F1F /* CodableExntensions.swift */; };
D2CDC3D42402D50A002B045F /* CodableExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DCA38E87F2B7196E0E1F1F /* CodableExtensions.swift */; };
D2CDC3D72404704D002B045F /* RecipientEmailsCellNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D24ABA6223FDB4FF002EE9DD /* RecipientEmailsCellNode.swift */; };
D2CDC3D824047066002B045F /* RecipientEmailNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2531F3523FFEDA2007E5198 /* RecipientEmailNode.swift */; };
D2CDC3DD24052D50002B045F /* FlowCryptUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D204DB9E23FB35700083B9D6 /* FlowCryptUI.framework */; };
Expand Down Expand Up @@ -448,7 +448,7 @@
21EA3B2E26565B7400691848 /* client_configuraion.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = client_configuraion.json; sourceTree = "<group>"; };
21EA3B3526565B8100691848 /* client_configuraion_empty.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = client_configuraion_empty.json; sourceTree = "<group>"; };
21EA3B3C26565B9800691848 /* client_configuraion_partly_empty.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = client_configuraion_partly_empty.json; sourceTree = "<group>"; };
21F836B52652A26B00B2448C /* DataExntensions+ZBase32Encoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataExntensions+ZBase32Encoding.swift"; sourceTree = "<group>"; };
21F836B52652A26B00B2448C /* DataExtensions+ZBase32Encoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataExtensions+ZBase32Encoding.swift"; sourceTree = "<group>"; };
21F836CB2652A38700B2448C /* ZBase32EncodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZBase32EncodingTests.swift; sourceTree = "<group>"; };
21F836D22652A46E00B2448C /* WKDURLsConstructorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKDURLsConstructorTests.swift; sourceTree = "<group>"; };
2C03CC15275BB53400887EEB /* EnterpriseServerApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterpriseServerApiTests.swift; sourceTree = "<group>"; };
Expand All @@ -470,7 +470,7 @@
32DCA0C3D34A69851A238E87 /* Core.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Core.swift; sourceTree = "<group>"; };
32DCA0E63F2F0473D0A8EDB0 /* StringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = "<group>"; };
32DCA377D22F4D67A8FA05EB /* Imap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Imap.swift; sourceTree = "<group>"; };
32DCA38E87F2B7196E0E1F1F /* CodableExntensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodableExntensions.swift; sourceTree = "<group>"; };
32DCA38E87F2B7196E0E1F1F /* CodableExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodableExtensions.swift; sourceTree = "<group>"; };
32DCA4B11D4531B3B04D01D1 /* AppErr.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppErr.swift; sourceTree = "<group>"; };
32DCA55C094E9745AA1FD210 /* Imap+msg.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Imap+msg.swift"; sourceTree = "<group>"; };
32DCA63656CB3323C26BC084 /* UIVIewExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIVIewExtensions.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -956,7 +956,7 @@
isa = PBXGroup;
children = (
32DCAEFF16F5D91A35791730 /* DataExtensions.swift */,
21F836B52652A26B00B2448C /* DataExntensions+ZBase32Encoding.swift */,
21F836B52652A26B00B2448C /* DataExtensions+ZBase32Encoding.swift */,
);
path = Data;
sourceTree = "<group>";
Expand Down Expand Up @@ -1879,7 +1879,7 @@
D2D27B78248A8694007346FA /* BigIntExtensions.swift */,
E26D5E20275AA417007B8802 /* BundleExtensions.swift */,
21C7DEFB26669A3700C44800 /* CalendarExtensions.swift */,
32DCA38E87F2B7196E0E1F1F /* CodableExntensions.swift */,
32DCA38E87F2B7196E0E1F1F /* CodableExtensions.swift */,
D2531F452402C62D007E5198 /* CollectionExtensions.swift */,
9F0C3C2723194E8500299985 /* CommonExtensions.swift */,
9F56BD3723438C7000A7371A /* DateFormattingExtensions.swift */,
Expand Down Expand Up @@ -2262,7 +2262,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1240;
LastUpgradeCheck = 1310;
LastUpgradeCheck = 1320;
ORGANIZATIONNAME = "FlowCrypt Limited";
TargetAttributes = {
9F2AC5C5267BE99E00F6149B = {
Expand Down Expand Up @@ -2845,7 +2845,7 @@
9F67998C277B3E4000AFE5BE /* BundleExtensions.swift in Sources */,
9FD5052B278B2C8600FAA82F /* UIPopoverPresentationControllerExtensions.swift in Sources */,
D2CDC3CD2402CCD7002B045F /* UIImageExtensions.swift in Sources */,
21F836B62652A26B00B2448C /* DataExntensions+ZBase32Encoding.swift in Sources */,
21F836B62652A26B00B2448C /* DataExtensions+ZBase32Encoding.swift in Sources */,
D29AFFF6240939AE00C1387D /* Then.swift in Sources */,
9FBD69EE27775086002FC602 /* ErrorExtensions.swift in Sources */,
9F6F5F6C26A2F66B00C625C7 /* Logger.swift in Sources */,
Expand All @@ -2862,7 +2862,7 @@
9FD5052927889D8200FAA82F /* UIAlertControllerExtensions.swift in Sources */,
9F8076D927762515008E5874 /* BigIntExtensions.swift in Sources */,
9FBD69EC27775086002FC602 /* UIApplicationExtensions.swift in Sources */,
D2CDC3D42402D50A002B045F /* CodableExntensions.swift in Sources */,
D2CDC3D42402D50A002B045F /* CodableExtensions.swift in Sources */,
9FD505272785C2CD00FAA82F /* UIDeviceExtensions.swift in Sources */,
D2531F3D24000E37007E5198 /* UIVIewExtensions.swift in Sources */,
D2531F3723FFF043007E5198 /* CommonExtensions.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
LastUpgradeVersion = "1320"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
LastUpgradeVersion = "1320"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
LastUpgradeVersion = "1320"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
LastUpgradeVersion = "1320"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
LastUpgradeVersion = "1320"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
LastUpgradeVersion = "1320"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
LastUpgradeVersion = "1320"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
8 changes: 4 additions & 4 deletions FlowCrypt.xcworkspace/xcshareddata/swiftpm/Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,17 @@
"repositoryURL": "https://github.com/realm/realm-cocoa",
"state": {
"branch": null,
"revision": "e83cc9f28e8bccd477b6b81cee521c02239d2773",
"version": "10.20.2"
"revision": "39177714b95bb5b1b29fffe28f1c7da77eef8e8b",
"version": "10.21.1"
}
},
{
"package": "RealmDatabase",
"repositoryURL": "https://github.com/realm/realm-core",
"state": {
"branch": null,
"revision": "c3c11a841642ac93c27bd1edd61f989fc0bfb809",
"version": "11.6.1"
"revision": "f1976f0d96d9b06fbe0afbd60090b1c3966b1e23",
"version": "11.8.0"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ extension ComposeViewController {
// TODO: - fix for spinner
// https://github.com/FlowCrypt/flowcrypt-ios/issues/291
try await Task.sleep(nanoseconds: 100 * 1_000_000) // 100ms

let sendableMsg = try await self.composeMessageService.validateAndProduceSendableMsg(
input: self.input,
contextToSend: self.contextToSend,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import UIKit


struct BackupViewDecorator {
let sceneTitle: String = "backup_screen_title"
.localized
Expand Down
Loading