Improve nsec password field requirements (fixes #1) and add more detailed descriptions.
This commit is contained in:
parent
0021db1c58
commit
8b4dba62e1
1 changed files with 230 additions and 15 deletions
|
@ -38,7 +38,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function loginWithNsec() {
|
function loginWithNsec() {
|
||||||
if (password.length < 8) return alert('Password must be at least 8 characters long');
|
if (password.length < 32) return alert('Password must be at least 32 characters long');
|
||||||
let nsecBytes = decodeKey(nsec);
|
let nsecBytes = decodeKey(nsec);
|
||||||
if (nsecBytes.type !== 'nsec') return alert('Invalid nsec');
|
if (nsecBytes.type !== 'nsec') return alert('Invalid nsec');
|
||||||
let encrypted = encryptNsec(nsecBytes.data, password);
|
let encrypted = encryptNsec(nsecBytes.data, password);
|
||||||
|
@ -75,22 +75,97 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if isLoggingIn}
|
{#if isLoggingIn}
|
||||||
|
<div class="login-warning">
|
||||||
|
<h3>🚨 Critical Security Warning 🚨</h3>
|
||||||
|
<p>Your nsec is the master key to your ENTIRE Nostr identity. If someone gets it:</p>
|
||||||
|
|
||||||
|
<ul class="warning-list">
|
||||||
|
<li>They can read ALL your letters - past and future</li>
|
||||||
|
<li>They can post ANYTHING pretending to be you</li>
|
||||||
|
<li>They can take over your account PERMANENTLY</li>
|
||||||
|
<li>There is NO WAY to undo this - not even we can help you</li>
|
||||||
|
<li>Your account would be LOST FOREVER</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class="warning-action">Only enter your nsec on devices you completely trust!</p>
|
||||||
|
<p class="warning-final">If you're not 100% sure about this, STOP and use a signing extension instead (or use
|
||||||
|
bunkers, coming soon).</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if ncryptsec || nsec}
|
{#if ncryptsec || nsec}
|
||||||
Enter your password: <br />
|
<h3>Password Required</h3>
|
||||||
If this is a new account make sure to remember the password in order to login later, if this is an existing account,
|
<p>
|
||||||
put in the same password you used to create the account. <br />
|
First time here? Create a strong password that is AT LEAST 32 characters long.<br>
|
||||||
<input bind:value={password} type="password" placeholder="Password" />
|
A good approach is to use 4-5 random words with numbers and symbols between them.<br>
|
||||||
<button onclick={cancelLoginWithNsec}>Cancel</button>
|
Example: correct-horse9battery!staple$running<br /><br />
|
||||||
{#if ncryptsec}
|
<a
|
||||||
<button onclick={loginWithExistingNcryptSec}>Login</button>
|
href="https://xkcd.com/936/"
|
||||||
{:else}
|
target="_blank"
|
||||||
<button onclick={loginWithNsec}>Login</button>
|
rel="noopener"
|
||||||
{/if}
|
class="button"
|
||||||
|
>
|
||||||
|
(See this XKCD comic for why this works)
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p class="warning-action">
|
||||||
|
Your password is used to encrypt your nsec. Write it down somewhere safe, it cannot be recovered.
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
bind:value={password}
|
||||||
|
type="password"
|
||||||
|
placeholder="Minimum 32 characters"
|
||||||
|
class="password-input"
|
||||||
|
/>
|
||||||
|
<div class="password-strength">
|
||||||
|
Length: {password?.length || 0}/32 characters
|
||||||
|
</div>
|
||||||
|
<div class="button-group">
|
||||||
|
<button onclick={cancelLoginWithNsec}>Go Back</button>
|
||||||
|
<button
|
||||||
|
onclick={ncryptsec ? loginWithExistingNcryptSec : loginWithNsec}
|
||||||
|
disabled={password?.length < 32}
|
||||||
|
>
|
||||||
|
Sign In
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
If you already have a nostr account, please enter your nsec below. If you don't have an nsec please use a nostr
|
<p>
|
||||||
client to create one, such as <a href="https://primal.net">Primal</a>.<br />
|
Already have a Nostr account? Enter your nsec below.<br>
|
||||||
<input bind:value={nsecField} type="password" placeholder="nsec1..." /><br />
|
Need an account? Create one using any of these popular clients:
|
||||||
<button onclick={nsecOk}>Ok</button>
|
</p>
|
||||||
|
<ul class="client-list">
|
||||||
|
<li>
|
||||||
|
<a href="https://primal.net" target="_blank" rel="noopener">
|
||||||
|
Primal
|
||||||
|
<span class="client-desc">Feature-rich web and mobile nostr client with great UI</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://damus.io" target="_blank" rel="noopener">
|
||||||
|
Damus
|
||||||
|
<span class="client-desc">Popular iOS nostr client</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://amethyst.social" target="_blank" rel="noopener">
|
||||||
|
Amethyst
|
||||||
|
<span class="client-desc">Feature-packed Android nostr client</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://iris.to" target="_blank" rel="noopener">
|
||||||
|
Iris
|
||||||
|
<span class="client-desc">Minimalist web nostr client</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<input
|
||||||
|
bind:value={nsecField}
|
||||||
|
type="password"
|
||||||
|
placeholder="nsec1..."
|
||||||
|
class="nsec-input"
|
||||||
|
/>
|
||||||
|
<button onclick={nsecOk}>Continue</button>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<button onclick={login}>Login with Nostr Extension</button>
|
<button onclick={login}>Login with Nostr Extension</button>
|
||||||
|
@ -102,4 +177,144 @@
|
||||||
display: block;
|
display: block;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-warning {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
margin-block: var(--spacing-md);
|
||||||
|
background: var(--glass-bg);
|
||||||
|
padding: var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-list {
|
||||||
|
list-style: none;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
margin: var(--spacing-md) 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
background: var(--glass-bg);
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: var(--spacing-sm);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
isolation: isolate;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: -2px;
|
||||||
|
background: linear-gradient(45deg, var(--accent), transparent);
|
||||||
|
border-radius: 10px;
|
||||||
|
z-index: -1;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 0 15px var(--glass-glow);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--text-primary);
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
.client-desc {
|
||||||
|
display: block;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin-top: var(--spacing-xs);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
margin: var(--spacing-md) 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
backdrop-filter: blur(var(--blur-strength));
|
||||||
|
background: var(--glass-bg-dark);
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: var(--spacing-sm);
|
||||||
|
color: var(--text-primary);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
box-shadow: var(--depth-shadow);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "⚠️";
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateX(var(--spacing-xs));
|
||||||
|
background: var(--glass-bg-darker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-action {
|
||||||
|
backdrop-filter: blur(var(--blur-strength));
|
||||||
|
background: var(--chip-error);
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: var(--spacing-md);
|
||||||
|
margin: var(--spacing-md) 0;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
box-shadow: var(--depth-shadow),
|
||||||
|
0 0 15px var(--glass-glow);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: color-mix(in srgb, var(--chip-error) 80%, black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-final {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
padding: var(--spacing-md) 0;
|
||||||
|
margin-top: var(--spacing-md);
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 80%;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
var(--chip-error),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
Loading…
Reference in a new issue