Add automatic SSL certificate generation
All checks were successful
Build and Push / build-all (push) Successful in 8m13s
All checks were successful
Build and Push / build-all (push) Successful in 8m13s
This commit is contained in:
parent
e13fffdaac
commit
42855330c0
11 changed files with 105 additions and 38 deletions
|
|
@ -152,6 +152,8 @@ class ChatWebSocket {
|
|||
...info,
|
||||
username: data.newName
|
||||
}));
|
||||
// Persist to localStorage for reconnection
|
||||
localStorage.setItem('guestName', data.newName);
|
||||
console.log('Rename successful:', data.newName);
|
||||
break;
|
||||
|
||||
|
|
@ -173,7 +175,10 @@ class ChatWebSocket {
|
|||
|
||||
case 'error':
|
||||
console.error('Chat error:', data.error);
|
||||
// Optionally show error to user
|
||||
// Show error to user
|
||||
if (data.error && typeof window !== 'undefined') {
|
||||
alert(data.error);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'mod_action_success':
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@
|
|||
msg = msg.replace(/^#\s+:(\w+):$/gm, (match, stickerName) => {
|
||||
const stickerKey = stickerName.toLowerCase();
|
||||
if (stickersMap[stickerKey]) {
|
||||
return `# <img src="${stickersMap[stickerKey]}" alt="${stickerName}" title="${stickerName}" data-sticker="${stickerName}" class="sticker-img" />`;
|
||||
return `# <img src="${stickersMap[stickerKey]}" alt="${stickerName}" title="${stickerName}" data-sticker="${stickerName}" class="sticker-img" onerror="this.onerror=null;this.src='/dlive2.gif';" />`;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
|
@ -153,7 +153,7 @@
|
|||
msg = msg.replace(/^##\s+:(\w+):$/gm, (match, stickerName) => {
|
||||
const stickerKey = stickerName.toLowerCase();
|
||||
if (stickersMap[stickerKey]) {
|
||||
return `## <img src="${stickersMap[stickerKey]}" alt="${stickerName}" title="${stickerName}" data-sticker="${stickerName}" class="sticker-img" />`;
|
||||
return `## <img src="${stickersMap[stickerKey]}" alt="${stickerName}" title="${stickerName}" data-sticker="${stickerName}" class="sticker-img" onerror="this.onerror=null;this.src='/dlive2.gif';" />`;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
|
@ -164,7 +164,7 @@
|
|||
msg = msg.replace(/:(\w+):/g, (match, stickerName) => {
|
||||
const stickerKey = stickerName.toLowerCase();
|
||||
if (stickersMap[stickerKey]) {
|
||||
return `<img src="${stickersMap[stickerKey]}" alt="${stickerName}" title="${stickerName}" data-sticker="${stickerName}" class="sticker-img" />`;
|
||||
return `<img src="${stickersMap[stickerKey]}" alt="${stickerName}" title="${stickerName}" data-sticker="${stickerName}" class="sticker-img" onerror="this.onerror=null;this.src='/dlive2.gif';" />`;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
|
@ -185,7 +185,7 @@
|
|||
// Step 5: Sanitize with DOMPurify - allow img tags and safe CSS
|
||||
html = DOMPurify.sanitize(html, {
|
||||
ALLOWED_TAGS: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'img', 'br', 'strong', 'em', 'code', 'pre', 'del', 'span'],
|
||||
ALLOWED_ATTR: ['src', 'alt', 'title', 'class', 'style', 'data-sticker'],
|
||||
ALLOWED_ATTR: ['src', 'alt', 'title', 'class', 'style', 'data-sticker', 'onerror'],
|
||||
FORBID_TAGS: ['a', 'button', 'script'],
|
||||
ALLOW_DATA_ATTR: false
|
||||
});
|
||||
|
|
|
|||
|
|
@ -271,16 +271,9 @@
|
|||
}
|
||||
|
||||
// Send rename message to server
|
||||
// Note: State updates (localStorage + store) happen in rename_success handler
|
||||
// to avoid updating UI before server confirms the rename
|
||||
if (chatWebSocket.sendRename(newGuestName.trim())) {
|
||||
// Store in localStorage for persistence
|
||||
localStorage.setItem('guestName', newGuestName.trim());
|
||||
|
||||
// Update local store
|
||||
chatUserInfo.update(info => ({
|
||||
...info,
|
||||
username: newGuestName.trim()
|
||||
}));
|
||||
|
||||
showRenameModal = false;
|
||||
newGuestName = '';
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@
|
|||
preview = preview.replace(/:(\w+):/g, (match, name) => {
|
||||
const key = name.toLowerCase();
|
||||
if (stickerMap && stickerMap[key]) {
|
||||
return `<img src="${stickerMap[key]}" alt="${name}" class="sticker-img-small" />`;
|
||||
return `<img src="${stickerMap[key]}" alt="${name}" class="sticker-img-small" onerror="this.onerror=null;this.src='/dlive2.gif';" />`;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
|
@ -147,7 +147,7 @@
|
|||
|
||||
return DOMPurify.sanitize(html, {
|
||||
ALLOWED_TAGS: ['p', 'img', 'br', 'strong', 'em', 'code', 'del', 'span'],
|
||||
ALLOWED_ATTR: ['src', 'alt', 'class'],
|
||||
ALLOWED_ATTR: ['src', 'alt', 'class', 'onerror'],
|
||||
FORBID_TAGS: ['a', 'button', 'script']
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@
|
|||
msg = msg.replace(/:(\w+):/g, (match, name) => {
|
||||
const key = name.toLowerCase();
|
||||
if (stickerMap && stickerMap[key]) {
|
||||
return `<img src="${stickerMap[key]}" alt="${name}" title="${name}" class="sticker-img" />`;
|
||||
return `<img src="${stickerMap[key]}" alt="${name}" title="${name}" class="sticker-img" onerror="this.onerror=null;this.src='/dlive2.gif';" />`;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
|
@ -125,7 +125,7 @@
|
|||
|
||||
return DOMPurify.sanitize(html, {
|
||||
ALLOWED_TAGS: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'img', 'br', 'strong', 'em', 'code', 'pre', 'del', 'span'],
|
||||
ALLOWED_ATTR: ['src', 'alt', 'title', 'class', 'style'],
|
||||
ALLOWED_ATTR: ['src', 'alt', 'title', 'class', 'style', 'onerror'],
|
||||
FORBID_TAGS: ['a', 'button', 'script']
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,12 +394,40 @@
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.fingerprint-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.fingerprint-display {
|
||||
font-family: monospace;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
|
||||
.key-origin-tag {
|
||||
display: inline-block;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.key-origin-tag.generated {
|
||||
background: rgba(40, 167, 69, 0.15);
|
||||
color: #28a745;
|
||||
border: 1px solid rgba(40, 167, 69, 0.3);
|
||||
}
|
||||
|
||||
.key-origin-tag.imported {
|
||||
background: rgba(0, 123, 255, 0.15);
|
||||
color: #007bff;
|
||||
border: 1px solid rgba(0, 123, 255, 0.3);
|
||||
}
|
||||
|
||||
.key-date {
|
||||
color: var(--gray);
|
||||
font-size: 0.85rem;
|
||||
|
|
@ -796,15 +824,20 @@
|
|||
{#if pgpKeys.length > 0}
|
||||
{#each pgpKeys as key}
|
||||
<div class="pgp-key-item">
|
||||
<div
|
||||
class="pgp-key-header"
|
||||
<div
|
||||
class="pgp-key-header"
|
||||
on:click={() => toggleKey(key.fingerprint)}
|
||||
on:keypress={(e) => e.key === 'Enter' && toggleKey(key.fingerprint)}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="pgp-key-info">
|
||||
<div class="fingerprint-display">{key.fingerprint}</div>
|
||||
<div class="fingerprint-row">
|
||||
<div class="fingerprint-display">{key.fingerprint}</div>
|
||||
<span class="key-origin-tag {key.keyOrigin || 'imported'}">
|
||||
{key.keyOrigin === 'generated' ? 'Generated' : 'Imported'}
|
||||
</span>
|
||||
</div>
|
||||
<div class="key-date">Added {new Date(key.createdAt).toLocaleDateString()}</div>
|
||||
</div>
|
||||
<span class="expand-icon" class:expanded={expandedKeys[key.fingerprint]}>
|
||||
|
|
|
|||
|
|
@ -932,7 +932,8 @@
|
|||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
publicKey: generatedPublicKey,
|
||||
fingerprint: fingerprint
|
||||
fingerprint: fingerprint,
|
||||
origin: 'generated'
|
||||
})
|
||||
});
|
||||
|
||||
|
|
@ -987,7 +988,8 @@
|
|||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
publicKey: newPublicKey,
|
||||
fingerprint
|
||||
fingerprint,
|
||||
origin: 'imported'
|
||||
})
|
||||
});
|
||||
|
||||
|
|
|
|||
BIN
frontend/static/dlive2.gif
Normal file
BIN
frontend/static/dlive2.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Loading…
Add table
Add a link
Reference in a new issue