Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7d405a1
removed dubious code
rrrooommmaaa Sep 14, 2021
8d602fe
fix
rrrooommmaaa Sep 15, 2021
329c733
Merge remote-tracking branch 'origin/master' into issue-2970-signing-…
rrrooommmaaa Sep 16, 2021
31374a7
support inline S/MIME armored message
rrrooommmaaa Sep 16, 2021
6d78d30
fix
rrrooommmaaa Sep 16, 2021
05a252e
fix
rrrooommmaaa Sep 16, 2021
061b542
Implemented S/MIME decryption
rrrooommmaaa Sep 17, 2021
6e1c966
Merge remote-tracking branch 'origin/master' into issue-2970-signing-…
rrrooommmaaa Sep 17, 2021
243c4d9
Merge remote-tracking branch 'origin/master' into issue-2970-signing-…
rrrooommmaaa Sep 20, 2021
fa81584
sign PKCS#7 message
rrrooommmaaa Sep 20, 2021
4c2f153
new types
rrrooommmaaa Sep 20, 2021
cd16fa8
PKCS#7 draft decryption
rrrooommmaaa Sep 23, 2021
9cf7cc7
Merge remote-tracking branch 'origin/master' into issue-2970-signing-…
rrrooommmaaa Sep 23, 2021
0332b47
Merge remote-tracking branch 'origin/master' into issue-2970-signing-…
rrrooommmaaa Sep 28, 2021
df989ef
small fixes
rrrooommmaaa Sep 28, 2021
10c7076
Merge remote-tracking branch 'origin/master' into issue-2970-signing-…
rrrooommmaaa Oct 5, 2021
2bb338f
removed unneeded remarks
rrrooommmaaa Oct 6, 2021
1e176c5
reading PKCS#7 message from DER
rrrooommmaaa Oct 6, 2021
3353ef2
removed unneeded remarks
rrrooommmaaa Oct 6, 2021
1adeb7f
removed code duplication
rrrooommmaaa Oct 6, 2021
78700b2
fix
rrrooommmaaa Oct 6, 2021
9cfa19e
more testing
rrrooommmaaa Oct 6, 2021
d310f1e
simplifications
rrrooommmaaa Oct 6, 2021
d6015ab
added some remarks
rrrooommmaaa Oct 6, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,6 @@ export class ComposeDraftModule extends ViewModule<ComposeView> {
} else {
prefix = `(saving of this draft was interrupted - to decrypt it, send it to yourself)\n\n`;
}
if (sendable.body['encrypted/buf']) {
sendable.body['encrypted/buf'] = Buf.concat([Buf.fromUtfStr(prefix), sendable.body['encrypted/buf']]);
}
if (sendable.body['text/plain']) {
sendable.body['text/plain'] = `${prefix}${sendable.body['text/plain'] || ''}`;
}
Expand Down Expand Up @@ -287,7 +284,7 @@ export class ComposeDraftModule extends ViewModule<ComposeView> {
}

private decryptAndRenderDraft = async (encrypted: MimeProccesedMsg): Promise<void> => {
const rawBlock = encrypted.blocks.find(b => b.type === 'encryptedMsg' || b.type === 'signedMsg');
const rawBlock = encrypted.blocks.find(b => ['encryptedMsg', 'signedMsg', 'pkcs7'].includes(b.type));
if (!rawBlock) {
return await this.abortAndRenderReplyMsgComposeTableIfIsReplyBox('!rawBlock');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter {
newMsg.pwd = undefined;
return await this.sendablePwdMsg(newMsg, pubkeys, msgUrl, signingPrv); // encrypted for pubkeys only, pwd ignored
} else if (this.richtext) { // rich text: PGP/MIME - https://tools.ietf.org/html/rfc3156#section-4
// or S/MIME
return await this.sendableRichTextMsg(newMsg, pubkeys, signingPrv);
} else { // simple text: PGP/Inline with attachments in separate files
} else { // simple text: PGP or S/MIME Inline with attachments in separate files
// todo: #4046 check attachments for S/MIME
return await this.sendableSimpleTextMsg(newMsg, pubkeys, signingPrv);
}
}
Expand Down Expand Up @@ -100,29 +102,35 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter {
private sendableSimpleTextMsg = async (newMsg: NewMsgData, pubs: PubkeyResult[], signingPrv?: Key): Promise<SendableMsg> => {
// todo - choosePubsBasedOnKeyTypeCombinationForPartialSmimeSupport is called later inside encryptDataArmor, could be refactored
const pubsForEncryption = KeyUtil.choosePubsBasedOnKeyTypeCombinationForPartialSmimeSupport(pubs);
if (this.isDraft) {
const { data: encrypted } = await this.encryptDataArmor(Buf.fromUtfStr(newMsg.plaintext), undefined, pubs, signingPrv);
return await SendableMsg.createInlineArmored(this.acctEmail, this.headers(newMsg), Buf.fromUint8(encrypted).toUtfStr(), [], { isDraft: this.isDraft });
}
const x509certs = pubsForEncryption.filter(pub => pub.type === 'x509');
if (x509certs.length) { // s/mime
const attachments: Attachment[] = this.isDraft ? [] : await this.view.attachmentsModule.attachment.collectAttachments(); // collects attachments
const msgBody = this.richtext ? { 'text/plain': newMsg.plaintext, 'text/html': newMsg.plainhtml } : { 'text/plain': newMsg.plaintext };
const msgBody = { 'text/plain': newMsg.plaintext };
const mimeEncodedPlainMessage = await Mime.encode(msgBody, { Subject: newMsg.subject }, attachments);
const encryptedMessage = await SmimeKey.encryptMessage({ pubkeys: x509certs, data: Buf.fromUtfStr(mimeEncodedPlainMessage) });
const encryptedMessage = await SmimeKey.encryptMessage({ pubkeys: x509certs, data: Buf.fromUtfStr(mimeEncodedPlainMessage), armor: false });
const data = encryptedMessage.data;
return await SendableMsg.createSMime(this.acctEmail, this.headers(newMsg), data, { isDraft: this.isDraft });
return await SendableMsg.createSMimeEncrypted(this.acctEmail, this.headers(newMsg), data, { isDraft: this.isDraft });
} else { // openpgp
const attachments: Attachment[] = this.isDraft ? [] : await this.view.attachmentsModule.attachment.collectEncryptAttachments(pubs);
const encrypted = await this.encryptDataArmor(Buf.fromUtfStr(newMsg.plaintext), undefined, pubs, signingPrv);
return await SendableMsg.createPgpInline(this.acctEmail, this.headers(newMsg), Buf.fromUint8(encrypted.data).toUtfStr(), attachments, { isDraft: this.isDraft });
return await SendableMsg.createInlineArmored(this.acctEmail, this.headers(newMsg), Buf.fromUint8(encrypted.data).toUtfStr(), attachments, { isDraft: this.isDraft });
}
}

private sendableRichTextMsg = async (newMsg: NewMsgData, pubs: PubkeyResult[], signingPrv?: Key) => {
// todo: pubs.type === 'x509' #4047
const plainAttachments = this.isDraft ? [] : await this.view.attachmentsModule.attachment.collectAttachments();
if (this.isDraft) { // this patch is needed as gmail makes it hard (or impossible) to render messages saved as https://tools.ietf.org/html/rfc3156
const pgpMimeToEncrypt = await Mime.encode({ 'text/plain': newMsg.plaintext, 'text/html': newMsg.plainhtml }, { Subject: newMsg.subject }, plainAttachments);
const { data: encrypted } = await this.encryptDataArmor(Buf.fromUtfStr(pgpMimeToEncrypt), undefined, pubs, signingPrv);
return await SendableMsg.createPgpInline(this.acctEmail, this.headers(newMsg), Buf.fromUint8(encrypted).toUtfStr(), plainAttachments, { isDraft: this.isDraft });
return await SendableMsg.createInlineArmored(this.acctEmail, this.headers(newMsg), Buf.fromUint8(encrypted).toUtfStr(), plainAttachments, { isDraft: this.isDraft });
}
const pgpMimeToEncrypt = await Mime.encode({ 'text/plain': newMsg.plaintext, 'text/html': newMsg.plainhtml }, { Subject: newMsg.subject }, plainAttachments);
// todo: don't armor S/MIME and decide what to do with attachments #4046 and #4047
const { data: encrypted } = await this.encryptDataArmor(Buf.fromUtfStr(pgpMimeToEncrypt), undefined, pubs, signingPrv);
const attachments = this.createPgpMimeAttachments(encrypted);
return await SendableMsg.createPgpMime(this.acctEmail, this.headers(newMsg), attachments, { isDraft: this.isDraft });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,26 @@ import { NewMsgData } from '../compose-types.js';
import { Key } from '../../../../js/common/core/crypto/key.js';
import { MsgUtil } from '../../../../js/common/core/crypto/pgp/msg-util.js';
import { SendableMsg } from '../../../../js/common/api/email-provider/sendable-msg.js';
import { SendableMsgBody } from '../../../../js/common/core/mime.js';
import { Mime, SendableMsgBody } from '../../../../js/common/core/mime.js';
import { ContactStore } from '../../../../js/common/platform/store/contact-store.js';
import { SmimeKey } from '../../../../js/common/core/crypto/smime/smime-key.js';
import { Buf } from '../../../../js/common/core/buf.js';

export class SignedMsgMailFormatter extends BaseMailFormatter {

public sendableMsg = async (newMsg: NewMsgData, signingPrv: Key): Promise<SendableMsg> => {
this.view.errModule.debug(`SignedMsgMailFormatter.sendableMsg signing with key: ${signingPrv.id}`);
const attachments = this.isDraft ? [] : await this.view.attachmentsModule.attachment.collectAttachments();
if (signingPrv.type === 'x509') {
// todo: attachments, richtext #4046, #4047
if (this.isDraft) {
throw new Error('signed-only PKCS#7 drafts are not supported');
}
const msgBody = this.richtext ? { 'text/plain': newMsg.plaintext, 'text/html': newMsg.plainhtml } : { 'text/plain': newMsg.plaintext };
const mimeEncodedPlainMessage = await Mime.encode(msgBody, { Subject: newMsg.subject }, attachments);
const data = await SmimeKey.sign(signingPrv, Buf.fromUtfStr(mimeEncodedPlainMessage));
return await SendableMsg.createSMimeSigned(this.acctEmail, this.headers(newMsg), data);
}
if (!this.richtext) {
// Folding the lines or GMAIL WILL RAPE THE TEXT, regardless of what encoding is used
// https://mathiasbynens.be/notes/gmail-plain-text applies to API as well
Expand All @@ -33,7 +45,7 @@ export class SignedMsgMailFormatter extends BaseMailFormatter {
const signedData = await MsgUtil.sign(signingPrv, newMsg.plaintext);
const allContacts = [...newMsg.recipients.to || [], ...newMsg.recipients.cc || [], ...newMsg.recipients.bcc || []];
ContactStore.update(undefined, allContacts, { lastUse: Date.now() }).catch(Catch.reportErr);
return await SendableMsg.createPgpInline(this.acctEmail, this.headers(newMsg), signedData, attachments);
return await SendableMsg.createInlineArmored(this.acctEmail, this.headers(newMsg), signedData, attachments);
}
// pgp/mime detached signature - it must be signed later, while being mime-encoded
// prepare a sign function first, which will be used by Mime.encodePgpMimeSigned later
Expand Down
25 changes: 15 additions & 10 deletions extension/js/common/api/email-provider/sendable-msg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Attachment } from '../../core/attachment.js';
import { Buf } from '../../core/buf.js';
import { RecipientType } from '../shared/api.js';
import { KeyStore } from '../../platform/store/key-store.js';
import { KeyUtil } from '../../core/crypto/key.js';

type Recipients = { to?: string[], cc?: string[], bcc?: string[] };

Expand Down Expand Up @@ -39,15 +40,19 @@ export class SendableMsg {

public sign?: (signable: string) => Promise<string>;

public static createSMime = async (acctEmail: string, headers: SendableMsgHeaders, data: Uint8Array, options: SendableMsgOptions): Promise<SendableMsg> => {
return await SendableMsg.createSendableMsg(acctEmail, headers, { "encrypted/buf": Buf.fromUint8(data) }, [], { type: 'smimeEncrypted', isDraft: options.isDraft });
public static createSMimeEncrypted = async (acctEmail: string, headers: SendableMsgHeaders, data: Uint8Array, options: SendableMsgOptions): Promise<SendableMsg> => {
return await SendableMsg.createSendableMsg(acctEmail, headers, { "pkcs7/buf": Buf.fromUint8(data) }, [], { type: 'smimeEncrypted', isDraft: options.isDraft });
}

public static createSMimeSigned = async (acctEmail: string, headers: SendableMsgHeaders, data: Uint8Array): Promise<SendableMsg> => {
return await SendableMsg.createSendableMsg(acctEmail, headers, { "pkcs7/buf": Buf.fromUint8(data) }, [], { type: 'smimeSigned' });
}

public static createPlain = async (acctEmail: string, headers: SendableMsgHeaders, body: SendableMsgBody, attachments: Attachment[]): Promise<SendableMsg> => {
return await SendableMsg.createSendableMsg(acctEmail, headers, body, attachments, { type: undefined, isDraft: undefined });
}

public static createPgpInline = async (acctEmail: string, headers: SendableMsgHeaders, body: string, attachments: Attachment[], options?: SendableMsgOptions): Promise<SendableMsg> => {
public static createInlineArmored = async (acctEmail: string, headers: SendableMsgHeaders, body: string, attachments: Attachment[], options?: SendableMsgOptions): Promise<SendableMsg> => {
return await SendableMsg.createSendableMsg(acctEmail, headers, { "text/plain": body }, attachments, options ? options : { type: undefined, isDraft: undefined });
}

Expand Down Expand Up @@ -91,7 +96,10 @@ export class SendableMsg {

private static create = async (acctEmail: string, { from, recipients, subject, thread, body, attachments, type, isDraft }: SendableMsgDefinition): Promise<SendableMsg> => {
const primaryKi = await KeyStore.getFirstRequired(acctEmail);
const headers: Dict<string> = primaryKi ? { OpenPGP: `id=${primaryKi.longid}` } : {}; // todo - use autocrypt format
const headers: Dict<string> = {};
if (primaryKi && KeyUtil.getKeyType(primaryKi.private) === 'openpgp') {
headers.Openpgp = `id=${primaryKi.longid}`; // todo - use autocrypt format
}
return new SendableMsg(
acctEmail,
headers,
Expand Down Expand Up @@ -138,14 +146,11 @@ export class SendableMsg {
}
}
this.headers.Subject = this.subject;
if (this.type === 'smimeEncrypted' && this.body['encrypted/buf']) {
return await Mime.encodeSmime(this.body['encrypted/buf'], this.headers);
if (this.body['pkcs7/buf']) {
return await Mime.encodeSmime(this.body['pkcs7/buf'], this.headers, this.type === 'smimeSigned' ? 'signed-data' : 'enveloped-data');
} else if (this.type === 'pgpMimeSigned' && this.sign) {
return await Mime.encodePgpMimeSigned(this.body, this.headers, this.attachments, this.sign);
} else { // encrypted/buf is a Buf instance that is converted to single-part plain/text message
if (this.body['encrypted/buf']) {
this.body = { 'text/plain': this.body['encrypted/buf'].toString() };
}
} else {
return await Mime.encode(this.body, this.headers, this.attachments, this.type);
}
}
Expand Down
36 changes: 17 additions & 19 deletions extension/js/common/core/crypto/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,21 +291,23 @@ export class KeyUtil {
}

public static choosePubsBasedOnKeyTypeCombinationForPartialSmimeSupport = (pubs: PubkeyResult[]): Key[] => {
const myPubs = pubs.filter(pub => pub.isMine); // currently this must be openpgp pub
const otherPgpPubs = pubs.filter(pub => !pub.isMine && pub.pubkey.type === 'openpgp');
const otherSmimePubs = pubs.filter(pub => !pub.isMine && pub.pubkey.type === 'x509');
if (otherPgpPubs.length && otherSmimePubs.length) {
let err = `Cannot use mixed OpenPGP (${otherPgpPubs.map(p => p.email).join(', ')}) and S/MIME (${otherSmimePubs.map(p => p.email).join(', ')}) public keys yet.`;
err += 'If you need to email S/MIME recipient, do not add any OpenPGP recipient at the same time.';
throw new UnreportableError(err);
}
if (otherPgpPubs.length) {
return myPubs.concat(...otherPgpPubs).map(p => p.pubkey);
}
if (otherSmimePubs.length) { // todo - currently skipping my own pgp keys when encrypting message for S/MIME
return otherSmimePubs.map(pub => pub.pubkey);
let pgpPubs = pubs.filter(pub => pub.pubkey.type === 'openpgp');
let smimePubs = pubs.filter(pub => pub.pubkey.type === 'x509');
if (pgpPubs.length && smimePubs.length) {
// get rid of some of my keys to resolve the conflict
// todo: how would it work with drafts?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drafts could be enabled only when we have at least one OpenPGP private key? Then make them OpenPGP?

In general, it's ok to explicitly disable functionality when user only imports S/MIME private key and nothing else. It's not a scenario we are designing for, even if it's allowed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented drafts for S/MIME because there were errors popping up when testing S/MIME user (without OpenPGP keys) editing a message (although "experimental"). I will disable such drafts completely, if you like.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it already works, no need to disable it. If you needed to spend a bunch of other work, then can disable as a way to save time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it works. I even added a test that loads an ecnrypted PKCS#7 draft. Was also planning on adding a test that saves a PKCS#7 draft, but will skip it, if you wish so.

if (smimePubs.every(pub => pub.isMine)) {
smimePubs = [];
} else if (pgpPubs.every(pub => pub.isMine)) {
pgpPubs = [];
} else {
let err = `Cannot use mixed OpenPGP (${pgpPubs.filter(p => !p.isMine).map(p => p.email).join(', ')}) and `
+ `S/MIME (${smimePubs.filter(p => !p.isMine).map(p => p.email).join(', ')}) public keys yet.`;
err += 'If you need to email S/MIME recipient, do not add any OpenPGP recipient at the same time.';
throw new UnreportableError(err);
}
}
return myPubs.map(p => p.pubkey);
return pgpPubs.concat(smimePubs).map(p => p.pubkey);
}

public static decrypt = async (key: Key, passphrase: string, optionalKeyid?: OpenPGP.Keyid, optionalBehaviorFlag?: 'OK-IF-ALREADY-DECRYPTED'): Promise<boolean> => {
Expand Down Expand Up @@ -369,11 +371,7 @@ export class KeyUtil {
if (pubkey.type !== 'x509') {
return OpenPGPKey.fingerprintToLongid(pubkey.id);
}
const encodedIssuerAndSerialNumber = 'X509-' + Buf.fromRawBytesStr(pubkey.issuerAndSerialNumber!).toBase64Str();
if (!encodedIssuerAndSerialNumber) {
throw new Error(`Cannot extract IssuerAndSerialNumber from the certificate for: ${pubkey.id}`);
}
return encodedIssuerAndSerialNumber;
return SmimeKey.getKeyLongid(pubkey);
}

public static getKeyInfoLongids = (ki: ExtendedKeyInfo): string[] => {
Expand Down
48 changes: 44 additions & 4 deletions extension/js/common/core/crypto/pgp/msg-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { PgpArmor, PreparedForDecrypt } from './pgp-armor.js';
import { opgp } from './openpgpjs-custom.js';
import { KeyCache } from '../../../platform/key-cache.js';
import { ContactStore } from '../../../platform/store/contact-store.js';
import { SmimeKey } from '../smime/smime-key.js';
import { SmimeKey, SmimeMsg } from '../smime/smime-key.js';
import { OpenPGPKey } from './openpgp-key.js';

export class DecryptionError extends Error {
Expand Down Expand Up @@ -210,22 +210,26 @@ export class MsgUtil {
} catch (formatErr) {
return { success: false, error: { type: DecryptErrTypes.format, message: String(formatErr) }, longids };
}
const keys = await MsgUtil.getSortedKeys(kisWithPp, prepared.message);
const keys = prepared.isPkcs7 ? await MsgUtil.getSmimeKeys(kisWithPp, prepared.message) : await MsgUtil.getSortedKeys(kisWithPp, prepared.message);
longids.message = keys.encryptedFor;
longids.matching = keys.prvForDecrypt.map(ki => ki.longid);
longids.chosen = keys.prvForDecryptDecrypted.map(decrypted => decrypted.ki.longid);
longids.needPassphrase = keys.prvForDecryptWithoutPassphrases.map(ki => ki.longid);
const isEncrypted = !prepared.isCleartext;
if (!isEncrypted) {
if (!isEncrypted && !prepared.isPkcs7) {
const signature = await MsgUtil.verify(prepared.message, keys.forVerification, keys.verificationContacts[0]);
const content = signature.content || Buf.fromUtfStr('no content');
signature.content = undefined; // no need to duplicate data
return { success: true, content, isEncrypted, signature };
}
if (!keys.prvForDecryptDecrypted.length && !msgPwd) {
if (!keys.prvForDecryptDecrypted.length && (!msgPwd || prepared.isPkcs7)) {
return { success: false, error: { type: DecryptErrTypes.needPassphrase, message: 'Missing pass phrase' }, longids, isEncrypted };
}
try {
if (prepared.isPkcs7) {
const decrypted = SmimeKey.decryptMessage(prepared.message, keys.prvForDecryptDecrypted[0].decrypted);
return { success: true, content: new Buf(decrypted), isEncrypted };
}
const packets = (prepared.message as OpenPGP.message.Message).packets;
const isSymEncrypted = packets.filter(p => p.tag === opgp.enums.packet.symEncryptedSessionKey).length > 0;
const isPubEncrypted = packets.filter(p => p.tag === opgp.enums.packet.publicKeyEncryptedSessionKey).length > 0;
Expand Down Expand Up @@ -338,6 +342,42 @@ export class MsgUtil {
return keys;
}

private static getSmimeKeys = async (kiWithPp: ExtendedKeyInfo[], msg: SmimeMsg): Promise<SortedKeysForDecrypt> => {
const keys: SortedKeysForDecrypt = {
verificationContacts: [],
forVerification: [],
encryptedFor: [],
signedBy: [],
prvMatching: [],
prvForDecrypt: [],
prvForDecryptDecrypted: [],
prvForDecryptWithoutPassphrases: [],
};
keys.encryptedFor = SmimeKey.getMessageLongids(msg);
if (keys.encryptedFor.length) {
keys.prvMatching = kiWithPp.filter(ki => KeyUtil.getKeyInfoLongids(ki).some(
longid => keys.encryptedFor.includes(longid)));
keys.prvForDecrypt = keys.prvMatching.length ? keys.prvMatching : kiWithPp;
} else { // prvs not needed for signed msgs
keys.prvForDecrypt = [];
}
for (const ki of keys.prvForDecrypt) {
const cachedKey = KeyCache.getDecrypted(ki.longid);
if (cachedKey) {
keys.prvForDecryptDecrypted.push({ ki, decrypted: cachedKey });
continue;
}
const parsed = await KeyUtil.parse(ki.private);
if (parsed.fullyDecrypted || ki.passphrase && await SmimeKey.decryptKey(parsed, ki.passphrase) === true) {
KeyCache.setDecrypted(parsed);
keys.prvForDecryptDecrypted.push({ ki, decrypted: parsed });
} else {
keys.prvForDecryptWithoutPassphrases.push(ki);
}
}
return keys;
}

private static matchingKeyids = (longids: string[], encryptedForKeyids: OpenPGP.Keyid[]): OpenPGP.Keyid[] => {
return encryptedForKeyids.filter(kid => longids.includes(OpenPGPKey.bytesToLongid(kid.bytes)));
}
Expand Down
Loading