Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
124fa2e
Update Settings - Security + Dangerzone by adding new buttons, styliz…
YuurinBee Feb 21, 2026
50b674d
Add Gitcoin as a Donor & Contributor in Settings
YuurinBee Feb 21, 2026
1409dfa
Add Footer in Settings with Donate, GitBook, and Privacy Policy Links
YuurinBee Feb 21, 2026
516b8f1
Polish Vector Popup Stylization
YuurinBee Feb 21, 2026
d20198c
Fix Sound Notifications Section, Sound Preview Button, Add Down Arrow…
YuurinBee Feb 23, 2026
a549bc4
Fix Image Viewer Contrast for Light Backgrounds
YuurinBee Feb 23, 2026
29d7753
Fix Top Avatar Bar Contrast + Shadow
YuurinBee Feb 23, 2026
9d70b55
Update Vector's main color to be mid-green tone, not accent
YuurinBee Feb 23, 2026
b545937
Add Scroll Effect to nPub Display
YuurinBee Feb 23, 2026
b96ef7a
Fix nPub Display > Truncated and add My Profile Top Nav Bar for Profile
YuurinBee Feb 23, 2026
b76e4fa
Edit New Chat Buttons on All Themes
YuurinBee Feb 23, 2026
c642012
Update Export Account Private Key Popup Design
YuurinBee Feb 23, 2026
f547f30
Add Title to Export Account Popup
YuurinBee Feb 23, 2026
dcef54a
Removing Typing Indicator Gradient Dead Code and Update Name
YuurinBee Feb 23, 2026
fe54bb3
Patch Key PIN Code Decryption Gradient
YuurinBee Feb 23, 2026
f540d9c
Fix width on Sound Preview button
YuurinBee Feb 23, 2026
303d581
Merge branch 'master' into frontend-upgrades
JSKitty Feb 25, 2026
0f4362c
fix: restore production app identifier (io.vectorapp)
JSKitty Feb 25, 2026
eb06746
fix: harden export popup XSS, hide Change PIN when encryption disable…
JSKitty Feb 25, 2026
b5d9e36
fix: add safety net for events.preview_metadata column missing on v0.…
JSKitty Feb 25, 2026
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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src-tauri/src/account_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,7 @@ fn run_migrations(conn: &mut rusqlite::Connection) -> Result<(), String> {
// migration system so they're always present regardless of migration history.
ensure_column_exists(conn, "mls_groups", "description", "TEXT")?;
ensure_column_exists(conn, "mls_groups", "avatar_cached", "TEXT")?;
ensure_column_exists(conn, "events", "preview_metadata", "TEXT")?;

// =========================================================================
// Migration 16: Create processed_wrappers table for NIP-59 gift wrap dedup
Expand Down
1 change: 1 addition & 0 deletions src/icons/gitcoin-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/icons/speaker_volume.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
106 changes: 67 additions & 39 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -578,19 +578,18 @@ <h3 id="profile-secondary-name" class="chat-contact-with-status btn"></h3>
<p class="navbar-text">Share</p>
</div>
</div>
<span id="profile-description" class="chat-contact-status" style="width: 90%; white-space: pre-line; overflow-y: auto; max-height: 225px; font-style: normal; margin-top: 10px;"></span>
<textarea id="profile-description-editor" class="chat-contact-status profile-description-editor" style="display: none; margin-top: 10px;"></textarea>
<div style="margin: 40px 0 0 0; width: 90%; padding-left: 5%;">
<h3 style="color: #f7f4f4; margin: 0; text-align: center;">nPub Key</h3>
</div>
<div id="profile-npub-container" class="profile-npub-container" style="margin-top: 5px; padding-top: 0;">
<span id="profile-npub" class="profile-npub"></span>
<button id="profile-npub-copy" class="btn profile-npub-copy">
<span class="icon icon-copy"></span>
</button>
</div>
<!-- Profile ID is currently JS-only, no visible UI - it will be added in the future -->
<span id="profile-id" style="display: none;"></span>
<span id="profile-description" class="chat-contact-status" style="width: 90%; white-space: pre-line; overflow-wrap: break-word; font-style: normal; margin-top: 10px; text-align: center; display: block;"></span>
<textarea id="profile-description-editor" class="chat-contact-status profile-description-editor" style="display: none; margin-top: 10px;"></textarea>
<div style="margin: 40px 0 0 0; width: 90%; padding-left: 5%;">
<h3 id="profile-npub-label" style="color: #f7f4f4; margin: 0; text-align: center;">nPub Key</h3>
</div>
<div id="profile-npub-container" class="profile-npub-container" style="margin-top: 5px; padding-top: 0;">
<span id="profile-npub" class="profile-npub"></span>
<button id="profile-npub-copy" class="btn profile-npub-copy">
<span class="icon icon-copy"></span>
</button>
</div>
<span id="profile-id" style="display: none;"></span>
</div>
</div>
</div>
Expand Down Expand Up @@ -888,21 +887,6 @@ <h2>Privacy</h2>
</div>
</div>

<!-- Security Settings Section -->
<div id="settings-security" class="settings-section">
<hr class="divider settings-divider">
<h2>Security</h2>

<div class="form-group">
<label class="toggle-container">
<span><span id="security-encryption-info" class="icon icon-info btn" style="width: 18px; height: 18px; position: relative; display: inline-block; vertical-align: text-top; margin-left: 5px;"></span>Local Encryption</span>
<input type="checkbox" id="security-encryption-toggle" checked>
<span class="neon-toggle"></span>
</label>
</div>
<button id="security-change-credential" class="btn cancel-btn" style="display: none;">Change PIN</button>
</div>

<!-- Display Settings Section -->
<div id="settings-display" class="settings-section">
<hr class="divider settings-divider">
Expand Down Expand Up @@ -938,16 +922,18 @@ <h2>Notifications</h2>
</label>
</div>

<div class="form-group">
<label for="notif-sound-select">Notification Sound</label>
<div class="select-container" style="margin-top: 10px;">
<select id="notif-sound-select">
<div class="form-group" style="display: flex; align-items: center; gap: 5px;">
<div class="select-container" style="margin: 0; flex: 1">
<select id="notif-sound-select" style="margin-bottom: 0 !important;">
<option value="default">Prélude</option>
<option value="techno">Techno</option>
<option value="none">None</option>
<option value="custom">Custom...</option>
</select>
</div>
<button id="notif-preview-btn" class="btn cancel-btn" style="margin: 0; padding: 0 10px; min-width: 42px; height: 42px; display: flex; align-items: center; justify-content: center;" title="Preview Sound">
<img src="./icons/speaker_volume.svg" alt="Preview" style="width: 18px; height: 18px;">
</button>
</div>

<div class="form-group" id="notif-custom-group" style="display: none;">
Expand All @@ -959,10 +945,6 @@ <h2>Notifications</h2>
</div>
</div>
</div>

<div class="form-group">
<button id="notif-preview-btn" class="btn cancel-btn">Preview Sound</button>
</div>
</div>

<!-- Battery & Background Service Section (mobile only) -->
Expand Down Expand Up @@ -1034,7 +1016,39 @@ <h3 style="font-size: 16px; margin-bottom: 10px;">What's New:</h3>
</div>
</div>

<!-- Action buttons -->
<!-- Security Settings Section -->
<div id="settings-security" class="settings-section">
<hr class="divider settings-divider">
<h2>Security</h2>

<div class="form-group">
<label class="toggle-container">
<span><span id="security-encryption-info" class="icon icon-info btn" style="width: 18px; height: 18px; position: relative; display: inline-block; vertical-align: text-top; margin-left: 5px;"></span>Local Encryption</span>
<input type="checkbox" id="security-encryption-toggle" checked>
<span class="neon-toggle"></span>
</label>
</div>

<div id="change-pin-container" class="danger-option" style="display: none;">
<div class="left-group">
<span id="change-pin-info" class="icon icon-info btn" style="width: 18px; height: 18px; position: relative; display: inline-block; vertical-align: text-top; margin-left: 5px;"></span>
<span id="change-pin-label">Change PIN</span>
</div>
<button id="security-change-credential" class="btn cancel-btn">Change</button>
</div>

<div class="danger-option">
<div class="left-group">
<span id="export-account-info" class="icon icon-info btn" style="width: 18px; height: 18px; position: relative; display: inline-block; vertical-align: text-top; margin-left: 5px;"></span>
<span>Export Account</span>
</div>
<button id="export-account-btn" class="cancel-btn">
Export
</button>
</div>
</div>

<!-- Dangerzone (Irreversible Actions) buttons -->
<button id="restart-update-btn" class="btn" style="display: none; margin-top: 10px; background: linear-gradient(135deg, #59fcb3 0%, #2b976c 100%);">Restart Now</button>
</div>
</div>
Expand Down Expand Up @@ -1086,16 +1100,30 @@ <h2 class="danger-title" style="margin-bottom: 0; margin-top: 0;">Dangerzone</h2

<!-- Donors & Contributors Section -->
<div id="settings-donors" class="settings-section" style="text-align: center;">
<hr class="divider settings-divider" style="background-color: #161616;">
<hr class="divider settings-divider" style="background-color: #171717;">
<h3 style="opacity: 0.6; font-weight: 500; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 5px;">Donors & Contributors
<span id="donors-info" class="icon icon-info btn" style="width: 16px; height: 16px; position: relative; display: inline-block; margin-left: 8px;"></span>
</h3>
<div class="donors-list" style="display: flex; flex-wrap: wrap; gap: 15px; justify-content: center; padding: 15px 0;">
<div class="donors-list" style="display: flex; flex-wrap: wrap; gap: 25px; justify-content: center; padding: 15px 0;">
<div id="donor-pivx" class="btn" style="cursor: pointer;">
<img src="./icons/PIVX-White.svg" alt="PIVX" style="height: 40px; width: auto;">
</div>
<div id="donor-gitcoin" class="btn" style="cursor: pointer;">
<img src="./icons/gitcoin-white.svg" alt="Gitcoin" style="height: 40px; width: auto;">
</div>
</div>
</div>

<!-- Footer Section (Hyperlinks)-->
<div class="settings-section">
<hr class="divider settings-divider" style="background-color: #171717;">
<div class="settings-footer" style="text-align: center; display: flex; gap: 20px; justify-content: center; flex-wrap: wrap;">
<span id="footer-donate" >Donate</span>
<span id="footer-gitbook">GitBook</span>
<span id="footer-privacy">Privacy Policy</span>
</div>
</div>

</div>

<div id="invites" style="display: none;">
Expand Down
4 changes: 2 additions & 2 deletions src/js/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ function createPlaceholderAvatar(isGroup = false, limitSizeTo = null) {
* @param {Boolean} fNotice - If this is a Notice or an Interactive Dialog.
* @param {String} strInputPlaceholder - If specified, renders a text input with a custom placeholder, and returns a string instead of a boolean.
* @param {String} strIcon - If specified, an icon to be displayed above the popup.
* @param {String} strTitleClass - If specified, a CSS class to be added to the title element (e.g., 'text-gradient').
* @param {String} strTitleClass - If specified, a CSS class to be added to the title element (e.g., 'typing-indicator-text').
* @return {Promise<Boolean>} - The Promise will resolve to 'true' if confirm button was clicked, otherwise 'false'.
*/
async function popupConfirm(strTitle, strSubtext, fNotice = false, strInputPlaceholder = '', strIcon = '', strTitleClass = '') {
Expand All @@ -196,7 +196,7 @@ async function popupConfirm(strTitle, strSubtext, fNotice = false, strInputPlace
domApp.classList.add('active');

// Adjust the 'Confirm' button if this is only a notice
domPopupConfirmBtn.innerText = fNotice ? 'Okay!' : 'Confirm';
domPopupConfirmBtn.innerText = fNotice ? 'Okay' : 'Confirm';
domPopupCancelBtn.style.display = fNotice ? 'none' : '';

// If a string placeholder is specified, render it
Expand Down
55 changes: 39 additions & 16 deletions src/js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -975,23 +975,46 @@ domSettingsExport.onclick = async (evt) => {
const keys = await invoke('export_keys');

// Create the export content with security warnings
let exportContent = `<h3>Account Export</h3>
<p style="color: #ff2ea9; font-weight: bold;">SECURITY WARNING</p>
<p>These are your private keys. Anyone with access to them can access your account.</p>
<p>Store them securely and never share them with anyone.</p><br>`;
// Escape values to prevent XSS from malicious DB content
const safeSeed = keys.seed_phrase ? escapeHtml(keys.seed_phrase) : '';
const safeNsec = escapeHtml(keys.nsec);

let exportContent = `
<div style="text-align: center; padding: 0 8px;">
<p style="color: #ff2ea9; font-weight: bold; font-size: 15px; margin: 0 0 10px 0;">Security Warning. Do Not Lose.</p>
<p style="opacity: 0.75; font-size: 13px; margin: 0 0 16px 0; word-break: break-word;">These keys are your identity on Vector. There are no recovery options! If lost, your account cannot be restored. Never share them.</p>
`;

// Add seed phrase first if available (prioritized for users)
if (keys.seed_phrase) {
exportContent += `<p><strong>Seed Phrase:</strong></p>
<p style="word-break: break-all; background: #1a1a1a; padding: 10px; border-radius: 5px; font-family: 'Courier New', monospace;">${keys.seed_phrase}</p><br>`;
exportContent += `
<div style="text-align: left; padding: 0 8px; margin-bottom: 12px;">
<p style="font-weight: bold; margin: 0 0 4px 0;">Seed Phrase</p>
<div style="display: flex; align-items: center; gap: 6px;">
<p id="export-seed-value" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; background: #1a1a1a; padding: 8px 10px; border-radius: 5px; font-family: monospace; font-size: 12px; flex: 1; margin: 0;">${safeSeed}</p>
<button id="export-seed-copy" style="flex-shrink: 0; padding: 6px 10px; border-radius: 5px; cursor: pointer;">Copy</button>
</div>
</div>
`;
}

// Always add the private key (nsec)
exportContent += `<p><strong>Private Key (nsec):</strong></p>
<p style="word-break: break-all; background: #1a1a1a; padding: 10px; border-radius: 5px; font-family: 'Courier New', monospace;">${keys.nsec}</p>`;
exportContent += `
<div style="text-align: center; padding: 0 8px;">
<p style="font-weight: bold; margin: 0 0 4px 0;">Private Key (nsec)</p>
<div style="display: flex; align-items: center; gap: 6px;">
<p id="export-nsec-value" style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; word-break: break-all; background: #1a1a1a; padding: 8px 10px; border-radius: 5px; font-family: monospace; font-size: 12px; flex: 1; margin: 0;">${safeNsec}</p>
</div>
<p style="color: #4de0a0; font-size: 12px; margin: 8px 0 -10px 0; text-align: center;">Do Not Store on Device. Backup Offline.</p>
</div>
`;

// Show the export information in a popup
await popupConfirm('', exportContent, true, '', 'vector_warning.svg');
await popupConfirm('Export Account', exportContent, true, '', 'vector_warning.svg');

// Bind copy buttons via DOM (safe — no inline onclick with interpolated values)
const seedCopyBtn = document.getElementById('export-seed-copy');
if (seedCopyBtn) seedCopyBtn.onclick = () => navigator.clipboard.writeText(keys.seed_phrase);
const nsecCopyBtn = document.getElementById('export-nsec-value');
if (nsecCopyBtn) nsecCopyBtn.style.cursor = 'pointer', nsecCopyBtn.onclick = () => navigator.clipboard.writeText(keys.nsec);
} catch (error) {
console.error('Export failed:', error);
await popupConfirm('Export Failed', escapeHtml(error.toString()), true, '', 'vector_warning.svg');
Expand Down Expand Up @@ -1673,13 +1696,13 @@ async function initEncryptionSettings() {
* Update change credential button visibility and text
*/
function updateChangeCredentialButton() {
const btn = document.getElementById('security-change-credential');
if (!btn) return;
const container = document.getElementById('change-pin-container');
if (!container) return;
if (fEncryptionEnabled) {
btn.style.display = '';
btn.textContent = fSecurityType === 'password' ? 'Change Password' : 'Change PIN';
container.style.display = '';
domSettingsChangePinLabel.textContent = fSecurityType === 'password' ? 'Change Password' : 'Change PIN';
} else {
btn.style.display = 'none';
container.style.display = 'none';
}
}

Expand Down
Loading