Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
57 changes: 51 additions & 6 deletions extension/chrome/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,24 +496,69 @@ View.run(
private addKeyRowsHtml = async (privateKeys: KeyInfoWithIdentity[]) => {
let html = '';
const canRemoveKey = !this.clientConfiguration?.usesKeyManager();

// 1. Parse and prepare data
const rows = [];
for (let i = 0; i < privateKeys.length; i++) {
const ki = privateKeys[i];
const prv = await KeyUtil.parse(ki.private);
const created = new Date(prv.created);
const date = Str.monthName(created.getMonth()) + ' ' + created.getDate() + ', ' + created.getFullYear();
const isExpired = KeyUtil.expired(prv);
rows.push({
ki,
prv,
createdTime: prv.created,
dateStr: date,
isExpired,
originalIndex: i,
});
}

// 2. Sort: newest to oldest
rows.sort((a, b) => b.createdTime - a.createdTime);

// 3. Build HTML
// Header row
html += `
<div class="row key-list-header" style="font-weight: 600; padding: 5px 0; border-bottom: 2px solid #eee;">
<div class="col-3">Email</div>
<div class="col-2">Created</div>
<div class="col-5">Fingerprint</div>
<div class="col-2">Status</div>
Comment on lines +527 to +528
Copy link
Collaborator

Choose a reason for hiding this comment

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

let's use col-6 for fingerprint and col-1 for status column, as currently fingerprint isn't fully fit on 1280px screen width:

Image

</div>
`;

for (const row of rows) {
const { ki, prv, dateStr, isExpired, originalIndex } = row;

let removeKeyBtn = '';
if (canRemoveKey && privateKeys.length > 1) {
removeKeyBtn = `(<a href="#" class="action_remove_key" data-test="action-remove-key-${i}" data-fingerprint=${ki.fingerprints[0]} data-type="${ki.family}" data-id="${ki.id}" data-longid="${ki.longid}">remove</a>)`;
removeKeyBtn = `<a href="#" class="action_remove_key" style="margin-left: 5px;" data-test="action-remove-key-${originalIndex}" data-fingerprint=${ki.fingerprints[0]} data-type="${ki.family}" data-id="${ki.id}" data-longid="${ki.longid}">remove</a>`;
}

const escapedEmail = Xss.escape(prv.emails[0] || '');
const escapedLink = `<a href="#" data-test="action-show-key-${i}" class="action_show_key" page="modules/my_key.htm" addurltext="&fingerprint=${ki.id}">${escapedEmail}</a>`;
const fpHtml = `fingerprint:&nbsp;<span class="good">${Str.spaced(Xss.escape(ki.fingerprints[0]))}</span>`;
const space = `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`;
html += `<div class="row key-content-row">`;
html += ` <div class="col-12">${escapedLink} from ${Xss.escape(date)}${space}${fpHtml}${space}${KeyUtil.statusHtml(ki.id, prv)}${space}${removeKeyBtn}</div>`;
const escapedLink = `<a href="#" data-test="action-show-key-${originalIndex}" class="action_show_key" page="modules/my_key.htm" addurltext="&fingerprint=${ki.id}">${escapedEmail}</a>`;
const fpHtml = `<span class="good" style="font-family: monospace;">${Str.spaced(Xss.escape(ki.fingerprints[0]))}</span>`;

const rowClass = isExpired ? 'key-content-row expired' : 'key-content-row';
const opacityStyle = isExpired ? 'opacity: 0.7;' : '';

// Compact layout: reduced padding via CSS (4px), no inline padding here.
// Added white-space: nowrap and overflow handling to keep single line.
Comment on lines +547 to +548
Copy link
Collaborator

Choose a reason for hiding this comment

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

no need for these comments, let's remove them

html += `<div class="row ${rowClass}" style="border-bottom: 1px solid #e6e6e6; align-items: center; ${opacityStyle}">`;
html += ` <div class="col-3" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${escapedLink}</div>`;
html += ` <div class="col-2" style="white-space: nowrap;">${Xss.escape(dateStr)}</div>`;
html += ` <div class="col-5" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${fpHtml}</div>`;
html += ` <div class="col-2" style="display: flex; justify-content: space-between; align-items: center; white-space: nowrap;">
${KeyUtil.statusHtml(ki.id, prv)}
${removeKeyBtn}
</div>`;
html += `</div>`;
}

Xss.sanitizeAppend('.key_list', html);

$('.action_show_key').on(
'click',
this.setHandler(async target => {
Expand Down
60 changes: 32 additions & 28 deletions extension/css/settings.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ html {
font-size: 14px;
}

#header-row .logo-row .subscription > span,
#header-row .logo-row .subscription > button {
#header-row .logo-row .subscription>span,
#header-row .logo-row .subscription>button {
Comment on lines +31 to +32
Copy link
Collaborator

Choose a reason for hiding this comment

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

looks like broken css formatting - there should be spaces around >

display: inline-block;
margin-left: 4px;
border: 1px solid #31a217;
border-radius: 3px;
padding: 0 5px;
}

#header-row .logo-row .subscription > button:focus {
#header-row .logo-row .subscription>button:focus {
outline: none;
box-shadow: inset 0 0 0 1px #fff;
}
Expand Down Expand Up @@ -201,7 +201,7 @@ a.gray_link {
margin: 0 auto !important;
}

.settings-icons-rows > div {
.settings-icons-rows>div {
min-width: 145px;
}

Expand Down Expand Up @@ -533,7 +533,7 @@ body#settings .settings-border .row {
}

body#settings .settings-border .key-content-row {
padding: 7px 0;
padding: 4px 0;
border-bottom: 1px solid #e6e6e6;
}

Expand All @@ -544,6 +544,10 @@ body#settings .settings-border .key_list {
height: 219px;
}

.key-content-row.expired {
opacity: 0.7;
}

#settings-row .box img.security-icon {
width: 70px;
}
Expand Down Expand Up @@ -583,21 +587,21 @@ body#settings .settings-border .key_list {
top: 28px;
}

@media (width <= 991px) {
@media (width <=991px) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

and here too

.my-keys-row .settings-border {
margin: 35px auto !important;
width: 100% !important;
}
}

@media (width <= 776px) {
@media (width <=776px) {
#public-profile-indicator {
left: 0;
right: 0;
}
}

@media (width <= 448px) {
@media (width <=448px) {
#footer-row {
position: relative;
}
Expand All @@ -608,7 +612,7 @@ body#settings .settings-border .key_list {
font-size: 14px;
}

#settings.client > #banner {
#settings.client>#banner {
background: white;
margin-left: 0;
margin-right: 0;
Expand Down Expand Up @@ -644,38 +648,38 @@ body#settings .settings-border .key_list {
padding-bottom: 200px;
}

#settings.client .threads > p {
#settings.client .threads>p {
padding-left: 20px;
opacity: 0.7;
}

#settings.client .threads > .line {
#settings.client .threads>.line {
padding-left: 20px;
text-align: left;
border-top: 1px solid #31a217;
padding-right: 20px;
width: auto;
}

#settings.client .threads > .line:last-child {
#settings.client .threads>.line:last-child {
border-bottom: 1px solid #31a217;
}

#settings.client .threads > .line.loaded:hover {
#settings.client .threads>.line.loaded:hover {
background-color: #fff;
cursor: pointer;
}

#settings.client .threads > .line .loading {
#settings.client .threads>.line .loading {
display: inline-block;
}

#settings.client .threads > .line .from_container {
#settings.client .threads>.line .from_container {
display: inline-block;
width: 300px;
}

#settings.client .threads > .line .from_container .msg_count {
#settings.client .threads>.line .from_container .msg_count {
font-size: 90%;
opacity: 0.5;
padding-left: 8px;
Expand All @@ -684,7 +688,7 @@ body#settings .settings-border .key_list {
}

/* #settings.client .threads .line .subject { } */
#settings.client .threads > .line .date {
#settings.client .threads>.line .date {
position: absolute;
right: 20px;
}
Expand All @@ -697,8 +701,8 @@ body#settings .settings-border .key_list {
border-top: 1px dotted #c0c0c0;
}

#settings.client .thread .message > iframe,
#settings.client .thread .reply > iframe {
#settings.client .thread .message>iframe,
#settings.client .thread .reply>iframe {
width: 100%;
border: none;
}
Expand All @@ -722,12 +726,12 @@ body#settings .settings-border .key_list {
cursor: pointer;
}

#settings.client > table {
#settings.client>table {
width: 100%;
min-height: 90%;
}

#settings.client > table td.menu {
#settings.client>table td.menu {
width: 200px;
min-width: 200px;
max-width: 200px;
Expand All @@ -736,14 +740,14 @@ body#settings .settings-border .key_list {
background: white;
}

#settings.client > table td.menu .button {
#settings.client>table td.menu .button {
min-width: 160px !important;
margin-bottom: 8px !important;
text-align: left !important;
white-space: nowrap;
}

#settings.client > table td.menu span.label {
#settings.client>table td.menu span.label {
margin-left: 0;
margin-bottom: 2px;
font-size: 12px;
Expand All @@ -754,7 +758,7 @@ body#settings .settings-border .key_list {
opacity: 0.7;
}

#settings.client > #banner > img {
#settings.client>#banner>img {
height: 32px;
width: 32px;
float: right;
Expand All @@ -763,19 +767,19 @@ body#settings .settings-border .key_list {
margin-left: 20px;
}

#settings.client > #banner > img.action_open_settings {
#settings.client>#banner>img.action_open_settings {
cursor: pointer;
}

#settings.client > #banner > .action_finish_session {
#settings.client>#banner>.action_finish_session {
height: 32px;
margin-top: -6px;
float: right;
margin-left: 20px;
cursor: pointer;
}

#settings.client > #banner > .action_finish_session img {
#settings.client>#banner>.action_finish_session img {
height: 32px;
}

Expand Down Expand Up @@ -847,4 +851,4 @@ span.fc-badge {
.fc-badge-light-gray {
background-color: #bcbcbc;
color: #444 !important;
}
}
6 changes: 3 additions & 3 deletions test/source/tests/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,7 @@ AN8G3r5Htj8olot+jm9mIa5XLXWzMNUZgg==
await addKeyPopup.waitAndType('@input-armored-key', updatedKey.privateKey);
await addKeyPopup.waitAndType('#input_passphrase', passphrase);
await addKeyPopup.waitAndClick('.action_add_private_key', { delay: 1 });
await Util.sleep(1);
await settingsPage.waitAll('@action-show-key-1');
await gmailPage.page.reload();
await Util.sleep(3);
await gmailPage.waitTillGone('@webmail-notification-notify_expiring_keys');
Expand Down Expand Up @@ -2250,15 +2250,15 @@ AN8G3r5Htj8olot+jm9mIa5XLXWzMNUZgg==
const title = await settingsPage.read('@container-overlay-prompt-text');
expect(title).to.contain(
'Failed to store newly generated key on FlowCrypt Email Key Manager, ' +
'No key has been generated for [email protected] yet. Please ask your administrator.'
'No key has been generated for [email protected] yet. Please ask your administrator.'
);
await settingsPage.click('@action-show-overlay-details');
await settingsPage.waitAll('@container-overlay-details');
await Util.sleep(0.5);
const details = await settingsPage.read('@container-overlay-details');
expect(details).to.contain(
`405 when PUT-ing https://localhost:${t.context.urls?.port}/flowcrypt-email-key-manager/v1/keys/private string: ` +
'privateKey -> No key has been generated for [email protected] yet'
'privateKey -> No key has been generated for [email protected] yet'
);
expect(details).to.not.contain('PRIVATE KEY');
})
Expand Down
Loading