Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
19 changes: 16 additions & 3 deletions extension/js/common/core/crypto/pgp/pgp-armor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,27 @@ export class PgpArmor {
}

public static clipIncomplete(text: string): string | undefined {
const match = text?.match(/(-----BEGIN PGP (MESSAGE|SIGNED MESSAGE|SIGNATURE|PUBLIC KEY BLOCK)-----[^]+)/gm);
// Prevent processing extremely large strings that could cause performance issues
const maxLength = 10 * 1024 * 1024; // 10MB limit
if (!text || text.length > maxLength) {
return undefined;
}

// Use [\s\S]+ instead of [^]+ to avoid potential regex issues
const match = text.match(/(-----BEGIN PGP (MESSAGE|SIGNED MESSAGE|SIGNATURE|PUBLIC KEY BLOCK)-----[\s\S]+)/gm);
return match?.length ? match[0] : undefined;
}

public static clip(text: string): string | undefined {
if (text?.includes(PgpArmor.ARMOR_HEADER_DICT.null.begin) && text.includes(String(PgpArmor.ARMOR_HEADER_DICT.null.end))) {
// Prevent processing extremely large strings that could cause performance issues
const maxLength = 10 * 1024 * 1024; // 10MB limit
if (!text || text.length > maxLength) {
return undefined;
}

if (text.includes(PgpArmor.ARMOR_HEADER_DICT.null.begin) && text.includes(String(PgpArmor.ARMOR_HEADER_DICT.null.end))) {
const match = text.match(
/(-----BEGIN PGP (MESSAGE|SIGNED MESSAGE|SIGNATURE|PUBLIC KEY BLOCK)-----[^]+-----END PGP (MESSAGE|SIGNATURE|PUBLIC KEY BLOCK)-----)/gm
/(-----BEGIN PGP MESSAGE-----[\s\S]*?-----END PGP MESSAGE-----|-----BEGIN PGP SIGNED MESSAGE-----[\s\S]*?-----END PGP SIGNATURE-----|-----BEGIN PGP SIGNATURE-----[\s\S]*?-----END PGP SIGNATURE-----|-----BEGIN PGP PUBLIC KEY BLOCK-----[\s\S]*?-----END PGP PUBLIC KEY BLOCK-----)/gm
);
return match?.length ? match[0] : undefined;
}
Expand Down
41 changes: 41 additions & 0 deletions test/source/tests/unit-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2762,6 +2762,47 @@ AAAAAAAAAAAAAAAAzzzzzzzzzzzzzzzzzzzzzzzzzzzz.....`)
t.pass();
});

test(`[unit][PgpArmor.clip] correctly handles all the cases including edge cases`, async t => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

great test improvement 👍

// Test empty and plain text
expect(PgpArmor.clip('')).to.be.an.undefined;
expect(PgpArmor.clip('plain text')).to.be.an.undefined;

// Test valid PGP messages
const validMessage = '-----BEGIN PGP MESSAGE-----\n\ntest content\n-----END PGP MESSAGE-----';
expect(PgpArmor.clip(validMessage)).to.equal(validMessage);

// Test with prefix and suffix
const messageWithNoise = 'prefix text ' + validMessage + ' suffix text';
expect(PgpArmor.clip(messageWithNoise)).to.equal(validMessage);

// Test multiple messages (should return first)
const multipleMessages = validMessage + '\n\n' + validMessage;
expect(PgpArmor.clip(multipleMessages)).to.equal(validMessage);

// Test with different block types
const publicKeyBlock = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nkey data\n-----END PGP PUBLIC KEY BLOCK-----';
expect(PgpArmor.clip(publicKeyBlock)).to.equal(publicKeyBlock);

// Test with signed message
const signedMessage = '-----BEGIN PGP SIGNED MESSAGE-----\n\nmessage\n-----BEGIN PGP SIGNATURE-----\nsig\n-----END PGP SIGNATURE-----';
expect(PgpArmor.clip(signedMessage)).to.equal(signedMessage);

// Test with mismatched begin/end (should not match)
const mismatchedMessage = '-----BEGIN PGP MESSAGE-----\n\ntest\n-----END PGP SIGNATURE-----';
expect(PgpArmor.clip(mismatchedMessage)).to.be.an.undefined;

// Test with very large input (over 10MB limit)
const largeInput = 'a'.repeat(11 * 1024 * 1024);
expect(PgpArmor.clip(largeInput)).to.be.an.undefined;

// Test with pathological input that would have caused stack overflow
const pathologicalBase = '-----BEGIN PGP MESSAGE-----\n' + 'a'.repeat(1000);
const pathologicalInput = pathologicalBase + '\n-----END PGP MESSAGE-----';
expect(PgpArmor.clip(pathologicalInput)).to.equal(pathologicalInput);

t.pass();
});

test(`[unit][Str] splitAlphanumericExtended returns all parts extendec till the end of the original string`, async t => {
expect(Str.splitAlphanumericExtended('[email protected]')).to.eql(['[email protected]', '[email protected]', 'part3.part4', 'part4']);
t.pass();
Expand Down
Loading