feat: install extension on insecure connections
Some checks failed
Docker build on tag / build (push) Has been cancelled
Some checks failed
Docker build on tag / build (push) Has been cancelled
This commit is contained in:
parent
424c7c79d7
commit
ff0f6efa29
@ -6,6 +6,10 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login p,
|
||||||
|
.login a {
|
||||||
color: #999999;
|
color: #999999;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,7 +25,7 @@
|
|||||||
|
|
||||||
.login .logo {
|
.login .logo {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
margin-bottom: 67px;
|
margin-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login > div:nth-child(1) {
|
.login > div:nth-child(1) {
|
||||||
@ -73,14 +77,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
|
.login {
|
||||||
|
width: unset;
|
||||||
|
height: unset;
|
||||||
|
}
|
||||||
|
|
||||||
.login > div:nth-child(2) {
|
.login > div:nth-child(2) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.login .login-note {
|
|
||||||
}
|
|
||||||
|
|
||||||
.login .login-actions {
|
.login .login-actions {
|
||||||
margin-top: 32px;
|
margin-top: 32px;
|
||||||
}
|
}
|
||||||
@ -99,20 +105,14 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
margin-top: 56px;
|
margin-top: 40px;
|
||||||
margin-bottom: 64px;
|
margin-bottom: 40px;
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 520px) {
|
|
||||||
.login .login-or {
|
|
||||||
margin-top: 32px;
|
|
||||||
margin-bottom: 32px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.light .login-or {
|
.light .login-or {
|
||||||
color: #a1a1aa;
|
color: #a1a1aa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-container input[type="text"] {
|
.login-container input[type="text"] {
|
||||||
border: none;
|
border: none;
|
||||||
background-color: var(--gray-secondary);
|
background-color: var(--gray-secondary);
|
||||||
|
@ -5,14 +5,14 @@ import { useDispatch, useSelector } from "react-redux";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import * as secp from "@noble/secp256k1";
|
import * as secp from "@noble/secp256k1";
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
|
import { HexKey } from "@snort/nostr";
|
||||||
|
|
||||||
import { RootState } from "State/Store";
|
import { RootState } from "State/Store";
|
||||||
import { setPrivateKey, setPublicKey, setRelays, setGeneratedPrivateKey } from "State/Login";
|
import { setPrivateKey, setPublicKey, setRelays, setGeneratedPrivateKey } from "State/Login";
|
||||||
import { DefaultRelays, EmailRegex, MnemonicRegex } from "Const";
|
import { DefaultRelays, EmailRegex, MnemonicRegex } from "Const";
|
||||||
import { bech32ToHex, generateBip39Entropy, entropyToDerivedKey, unwrap } from "Util";
|
import { bech32ToHex, generateBip39Entropy, entropyToDerivedKey, unwrap } from "Util";
|
||||||
import { HexKey } from "@snort/nostr";
|
|
||||||
import ZapButton from "Element/ZapButton";
|
import ZapButton from "Element/ZapButton";
|
||||||
// import useImgProxy from "Feed/ImgProxy";
|
import useImgProxy from "Hooks/useImgProxy";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
|
||||||
@ -67,7 +67,9 @@ export default function LoginPage() {
|
|||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [art, setArt] = useState<ArtworkEntry>();
|
const [art, setArt] = useState<ArtworkEntry>();
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
//const { proxy } = useImgProxy();
|
const { proxy } = useImgProxy();
|
||||||
|
const hasNip7 = "nostr" in window;
|
||||||
|
const isSecure = window.location.protocol === "https:";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (publicKey) {
|
if (publicKey) {
|
||||||
@ -77,14 +79,19 @@ export default function LoginPage() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ret = unwrap(Artwork.at(Artwork.length * Math.random()));
|
const ret = unwrap(Artwork.at(Artwork.length * Math.random()));
|
||||||
// disable for now because imgproxy is ded
|
proxy(ret.link).then(a => setArt({ ...ret, link: a }));
|
||||||
// proxy(ret.link).then(a => setArt({ ...ret, link: a }));
|
|
||||||
setArt(ret);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
async function doLogin() {
|
async function doLogin() {
|
||||||
|
const insecureMsg = formatMessage({
|
||||||
|
defaultMessage:
|
||||||
|
"Can't login with private key on an insecure connection, please use a Nostr key manager extension instead",
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
if (key.startsWith("nsec")) {
|
if (key.startsWith("nsec")) {
|
||||||
|
if (!isSecure) {
|
||||||
|
throw new Error(insecureMsg);
|
||||||
|
}
|
||||||
const hexKey = bech32ToHex(key);
|
const hexKey = bech32ToHex(key);
|
||||||
if (secp.utils.isValidPrivateKey(hexKey)) {
|
if (secp.utils.isValidPrivateKey(hexKey)) {
|
||||||
dispatch(setPrivateKey(hexKey));
|
dispatch(setPrivateKey(hexKey));
|
||||||
@ -98,16 +105,30 @@ export default function LoginPage() {
|
|||||||
const hexKey = await getNip05PubKey(key);
|
const hexKey = await getNip05PubKey(key);
|
||||||
dispatch(setPublicKey(hexKey));
|
dispatch(setPublicKey(hexKey));
|
||||||
} else if (key.match(MnemonicRegex)) {
|
} else if (key.match(MnemonicRegex)) {
|
||||||
|
if (!isSecure) {
|
||||||
|
throw new Error(insecureMsg);
|
||||||
|
}
|
||||||
const ent = generateBip39Entropy(key);
|
const ent = generateBip39Entropy(key);
|
||||||
const keyHex = entropyToDerivedKey(ent);
|
const keyHex = entropyToDerivedKey(ent);
|
||||||
dispatch(setPrivateKey(keyHex));
|
dispatch(setPrivateKey(keyHex));
|
||||||
} else if (secp.utils.isValidPrivateKey(key)) {
|
} else if (secp.utils.isValidPrivateKey(key)) {
|
||||||
|
if (!isSecure) {
|
||||||
|
throw new Error(insecureMsg);
|
||||||
|
}
|
||||||
dispatch(setPrivateKey(key));
|
dispatch(setPrivateKey(key));
|
||||||
} else {
|
} else {
|
||||||
throw new Error("INVALID PRIVATE KEY");
|
throw new Error("INVALID PRIVATE KEY");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(`Failed to load NIP-05 pub key (${e})`);
|
if (e instanceof Error) {
|
||||||
|
setError(e.message);
|
||||||
|
} else {
|
||||||
|
setError(
|
||||||
|
formatMessage({
|
||||||
|
defaultMessage: "Unknown login error",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,9 +160,8 @@ export default function LoginPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function altLogins() {
|
function altLogins() {
|
||||||
const nip07 = "nostr" in window;
|
if (!hasNip7) {
|
||||||
if (!nip07) {
|
return;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -154,6 +174,92 @@ export default function LoginPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateKey() {
|
||||||
|
if (!isSecure) return;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex login-or">
|
||||||
|
<FormattedMessage defaultMessage="OR" description="Seperator text for Login / Generate Key" />
|
||||||
|
<div className="divider w-max"></div>
|
||||||
|
</div>
|
||||||
|
<h1 dir="auto">
|
||||||
|
<FormattedMessage defaultMessage="Create an Account" description="Heading for generate key flow" />
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Generate a public / private key pair. Do not share your private key with anyone, this acts as your password. Once lost, it cannot be “reset” or recovered. Keep safe!"
|
||||||
|
description="Note about key security before generating a new key"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<div className="login-actions">
|
||||||
|
<button type="button" onClick={() => makeRandomKey()}>
|
||||||
|
<FormattedMessage defaultMessage="Generate Key" description="Button: Generate a new key" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function installExtension() {
|
||||||
|
if (isSecure) return;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex login-or">
|
||||||
|
<FormattedMessage defaultMessage="OR" description="Seperator text for Login / Generate Key" />
|
||||||
|
<div className="divider w-max"></div>
|
||||||
|
</div>
|
||||||
|
<h1 dir="auto">
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Install Extension"
|
||||||
|
description="Heading for install key manager extension"
|
||||||
|
/>
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage defaultMessage="Key manager extensions are more secure and allow you to easily login to any Nostr client, here are some well known extensions:" />
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://getalby.com/" target="_blank" rel="noreferrer">
|
||||||
|
Alby
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://chrome.google.com/webstore/detail/nos2x/kpgefcfmnafjgpblomihpgmejjdanjjp"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer">
|
||||||
|
nos2x
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="If you want to try out some others, check out {link} for more!"
|
||||||
|
values={{
|
||||||
|
link: <a href="https://github.com/aljazceru/awesome-nostr#browser-extensions">awesome-nostr</a>,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage defaultMessage="Once you setup your key manager extension and generated a key, you can follow our new users flow to setup your profile and help you find some interesting people on Nostr to follow." />
|
||||||
|
</p>
|
||||||
|
{hasNip7 ? (
|
||||||
|
<div className="login-actions">
|
||||||
|
<button type="button" onClick={() => doNip07Login().then(() => navigate("/new/username"))}>
|
||||||
|
<FormattedMessage defaultMessage="Setup Profile" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<b className="error">
|
||||||
|
<FormattedMessage defaultMessage="Hmm, can't find a key manager extension.. try reloading the page." />
|
||||||
|
</b>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="login">
|
<div className="login">
|
||||||
<div>
|
<div>
|
||||||
@ -183,36 +289,14 @@ export default function LoginPage() {
|
|||||||
description="Explanation for public key only login is read-only"
|
description="Explanation for public key only login is read-only"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
{/* <a href="">
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Why is there no password field?"
|
|
||||||
description="Link to why your private key is your password"
|
|
||||||
/>
|
|
||||||
</a>*/}
|
|
||||||
<div dir="auto" className="login-actions">
|
<div dir="auto" className="login-actions">
|
||||||
<button type="button" onClick={doLogin}>
|
<button type="button" onClick={doLogin}>
|
||||||
<FormattedMessage defaultMessage="Login" description="Login button" />
|
<FormattedMessage defaultMessage="Login" description="Login button" />
|
||||||
</button>
|
</button>
|
||||||
{altLogins()}
|
{altLogins()}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex login-or">
|
{generateKey()}
|
||||||
<FormattedMessage defaultMessage="OR" description="Seperator text for Login / Generate Key" />
|
{installExtension()}
|
||||||
<div className="divider w-max"></div>
|
|
||||||
</div>
|
|
||||||
<h1 dir="auto">
|
|
||||||
<FormattedMessage defaultMessage="Create an Account" description="Heading for generate key flow" />
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Generate a public / private key pair. Do not share your private key with anyone, this acts as your password. Once lost, it cannot be “reset” or recovered. Keep safe!"
|
|
||||||
description="Note about key security before generating a new key"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<div className="login-actions">
|
|
||||||
<button type="button" onClick={() => makeRandomKey()}>
|
|
||||||
<FormattedMessage defaultMessage="Generate Key" description="Button: Generate a new key" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -118,6 +118,9 @@
|
|||||||
"4rYCjn": {
|
"4rYCjn": {
|
||||||
"defaultMessage": "Note to Self"
|
"defaultMessage": "Note to Self"
|
||||||
},
|
},
|
||||||
|
"5rOdPG": {
|
||||||
|
"defaultMessage": "Once you setup your key manager extension and generated a key, you can follow our new users flow to setup your profile and help you find some interesting people on Nostr to follow."
|
||||||
|
},
|
||||||
"5ykRmX": {
|
"5ykRmX": {
|
||||||
"defaultMessage": "Send zap"
|
"defaultMessage": "Send zap"
|
||||||
},
|
},
|
||||||
@ -410,6 +413,9 @@
|
|||||||
"OKhRC6": {
|
"OKhRC6": {
|
||||||
"defaultMessage": "Share"
|
"defaultMessage": "Share"
|
||||||
},
|
},
|
||||||
|
"OLEm6z": {
|
||||||
|
"defaultMessage": "Unknown login error"
|
||||||
|
},
|
||||||
"P61BTu": {
|
"P61BTu": {
|
||||||
"defaultMessage": "Copy Event JSON"
|
"defaultMessage": "Copy Event JSON"
|
||||||
},
|
},
|
||||||
@ -479,6 +485,9 @@
|
|||||||
"Up5U7K": {
|
"Up5U7K": {
|
||||||
"defaultMessage": "Block"
|
"defaultMessage": "Block"
|
||||||
},
|
},
|
||||||
|
"VBadwB": {
|
||||||
|
"defaultMessage": "Hmm, can't find a key manager extension.. try reloading the page."
|
||||||
|
},
|
||||||
"VN0+Fz": {
|
"VN0+Fz": {
|
||||||
"defaultMessage": "Balance: {amount} sats"
|
"defaultMessage": "Balance: {amount} sats"
|
||||||
},
|
},
|
||||||
@ -516,6 +525,9 @@
|
|||||||
"XgWvGA": {
|
"XgWvGA": {
|
||||||
"defaultMessage": "Reactions"
|
"defaultMessage": "Reactions"
|
||||||
},
|
},
|
||||||
|
"XzF0aC": {
|
||||||
|
"defaultMessage": "Key manager extensions are more secure and allow you to easily login to any Nostr client, here are some well known extensions:"
|
||||||
|
},
|
||||||
"Y31HTH": {
|
"Y31HTH": {
|
||||||
"defaultMessage": "Help fund the development of Snort"
|
"defaultMessage": "Help fund the development of Snort"
|
||||||
},
|
},
|
||||||
@ -549,6 +561,10 @@
|
|||||||
"bxv59V": {
|
"bxv59V": {
|
||||||
"defaultMessage": "Just now"
|
"defaultMessage": "Just now"
|
||||||
},
|
},
|
||||||
|
"c+oiJe": {
|
||||||
|
"defaultMessage": "Install Extension",
|
||||||
|
"description": "Heading for install key manager extension"
|
||||||
|
},
|
||||||
"c35bj2": {
|
"c35bj2": {
|
||||||
"defaultMessage": "If you have an enquiry about your NIP-05 order please DM {link}"
|
"defaultMessage": "If you have an enquiry about your NIP-05 order please DM {link}"
|
||||||
},
|
},
|
||||||
@ -687,6 +703,9 @@
|
|||||||
"kaaf1E": {
|
"kaaf1E": {
|
||||||
"defaultMessage": "now"
|
"defaultMessage": "now"
|
||||||
},
|
},
|
||||||
|
"lBboHo": {
|
||||||
|
"defaultMessage": "If you want to try out some others, check out {link} for more!"
|
||||||
|
},
|
||||||
"lCILNz": {
|
"lCILNz": {
|
||||||
"defaultMessage": "Buy Now"
|
"defaultMessage": "Buy Now"
|
||||||
},
|
},
|
||||||
@ -735,6 +754,9 @@
|
|||||||
"nN9XTz": {
|
"nN9XTz": {
|
||||||
"defaultMessage": "Share your thoughts with {link}"
|
"defaultMessage": "Share your thoughts with {link}"
|
||||||
},
|
},
|
||||||
|
"nOaArs": {
|
||||||
|
"defaultMessage": "Setup Profile"
|
||||||
|
},
|
||||||
"nn1qb3": {
|
"nn1qb3": {
|
||||||
"defaultMessage": "Your donations are greatly appreciated"
|
"defaultMessage": "Your donations are greatly appreciated"
|
||||||
},
|
},
|
||||||
@ -833,6 +855,9 @@
|
|||||||
"uSV4Ti": {
|
"uSV4Ti": {
|
||||||
"defaultMessage": "Reposts need to be manually confirmed"
|
"defaultMessage": "Reposts need to be manually confirmed"
|
||||||
},
|
},
|
||||||
|
"ubtr9S": {
|
||||||
|
"defaultMessage": "Can't login with private key on 'http://' connection, please use a Nostr key manager extension instead"
|
||||||
|
},
|
||||||
"usAvMr": {
|
"usAvMr": {
|
||||||
"defaultMessage": "Edit Profile"
|
"defaultMessage": "Edit Profile"
|
||||||
},
|
},
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
"4Vmpt4": "Nostr Plebs is one of the first NIP-05 providers in the space and offers a good collection of domains at reasonable prices",
|
"4Vmpt4": "Nostr Plebs is one of the first NIP-05 providers in the space and offers a good collection of domains at reasonable prices",
|
||||||
"4Z3t5i": "Use imgproxy to compress images",
|
"4Z3t5i": "Use imgproxy to compress images",
|
||||||
"4rYCjn": "Note to Self",
|
"4rYCjn": "Note to Self",
|
||||||
|
"5rOdPG": "Once you setup your key manager extension and generated a key, you can follow our new users flow to setup your profile and help you find some interesting people on Nostr to follow.",
|
||||||
"5ykRmX": "Send zap",
|
"5ykRmX": "Send zap",
|
||||||
"6ewQqw": "Likes ({n})",
|
"6ewQqw": "Likes ({n})",
|
||||||
"6tUqAb": "Generate a public / private key pair. Do not share your private key with anyone, this acts as your password. Once lost, it cannot be “reset” or recovered. Keep safe!",
|
"6tUqAb": "Generate a public / private key pair. Do not share your private key with anyone, this acts as your password. Once lost, it cannot be “reset” or recovered. Keep safe!",
|
||||||
@ -133,6 +134,7 @@
|
|||||||
"NndBJE": "New users page",
|
"NndBJE": "New users page",
|
||||||
"OEW7yJ": "Zaps",
|
"OEW7yJ": "Zaps",
|
||||||
"OKhRC6": "Share",
|
"OKhRC6": "Share",
|
||||||
|
"OLEm6z": "Unknown login error",
|
||||||
"P61BTu": "Copy Event JSON",
|
"P61BTu": "Copy Event JSON",
|
||||||
"P7FD0F": "System (Default)",
|
"P7FD0F": "System (Default)",
|
||||||
"P7nJT9": "Total today (UTC): {amount} sats",
|
"P7nJT9": "Total today (UTC): {amount} sats",
|
||||||
@ -155,6 +157,7 @@
|
|||||||
"TpgeGw": "Hex Salt..",
|
"TpgeGw": "Hex Salt..",
|
||||||
"UQ3pOC": "On Nostr, many people have the same username. User names and identity are separate things. You can get a unique identifier in the next step.",
|
"UQ3pOC": "On Nostr, many people have the same username. User names and identity are separate things. You can get a unique identifier in the next step.",
|
||||||
"Up5U7K": "Block",
|
"Up5U7K": "Block",
|
||||||
|
"VBadwB": "Hmm, can't find a key manager extension.. try reloading the page.",
|
||||||
"VN0+Fz": "Balance: {amount} sats",
|
"VN0+Fz": "Balance: {amount} sats",
|
||||||
"VOjC1i": "Pick which upload service you want to upload attachments to",
|
"VOjC1i": "Pick which upload service you want to upload attachments to",
|
||||||
"VlJkSk": "{n} muted",
|
"VlJkSk": "{n} muted",
|
||||||
@ -167,6 +170,7 @@
|
|||||||
"WxthCV": "e.g. Jack",
|
"WxthCV": "e.g. Jack",
|
||||||
"X7xU8J": "nsec, npub, nip-05, hex, mnemonic",
|
"X7xU8J": "nsec, npub, nip-05, hex, mnemonic",
|
||||||
"XgWvGA": "Reactions",
|
"XgWvGA": "Reactions",
|
||||||
|
"XzF0aC": "Key manager extensions are more secure and allow you to easily login to any Nostr client, here are some well known extensions:",
|
||||||
"Y31HTH": "Help fund the development of Snort",
|
"Y31HTH": "Help fund the development of Snort",
|
||||||
"YDURw6": "Service URL",
|
"YDURw6": "Service URL",
|
||||||
"YXA3AH": "Enable reactions",
|
"YXA3AH": "Enable reactions",
|
||||||
@ -178,6 +182,7 @@
|
|||||||
"aWpBzj": "Show more",
|
"aWpBzj": "Show more",
|
||||||
"brAXSu": "Pick a username",
|
"brAXSu": "Pick a username",
|
||||||
"bxv59V": "Just now",
|
"bxv59V": "Just now",
|
||||||
|
"c+oiJe": "Install Extension",
|
||||||
"c35bj2": "If you have an enquiry about your NIP-05 order please DM {link}",
|
"c35bj2": "If you have an enquiry about your NIP-05 order please DM {link}",
|
||||||
"cPIKU2": "Following",
|
"cPIKU2": "Following",
|
||||||
"cQfLWb": "URL..",
|
"cQfLWb": "URL..",
|
||||||
@ -223,6 +228,7 @@
|
|||||||
"k2veDA": "Write",
|
"k2veDA": "Write",
|
||||||
"k7sKNy": "Our very own NIP-05 verification service, help support the development of this site and get a shiny special badge on our site!",
|
"k7sKNy": "Our very own NIP-05 verification service, help support the development of this site and get a shiny special badge on our site!",
|
||||||
"kaaf1E": "now",
|
"kaaf1E": "now",
|
||||||
|
"lBboHo": "If you want to try out some others, check out {link} for more!",
|
||||||
"lCILNz": "Buy Now",
|
"lCILNz": "Buy Now",
|
||||||
"lD3+8a": "Pay",
|
"lD3+8a": "Pay",
|
||||||
"lTbT3s": "Wallet password",
|
"lTbT3s": "Wallet password",
|
||||||
@ -239,6 +245,7 @@
|
|||||||
"nDejmx": "Unblock",
|
"nDejmx": "Unblock",
|
||||||
"nGBrvw": "Bookmarks",
|
"nGBrvw": "Bookmarks",
|
||||||
"nN9XTz": "Share your thoughts with {link}",
|
"nN9XTz": "Share your thoughts with {link}",
|
||||||
|
"nOaArs": "Setup Profile",
|
||||||
"nn1qb3": "Your donations are greatly appreciated",
|
"nn1qb3": "Your donations are greatly appreciated",
|
||||||
"nwZXeh": "{n} blocked",
|
"nwZXeh": "{n} blocked",
|
||||||
"o6Uy3d": "Only the secret key can be used to publish (sign events), everything else logs you in read-only mode.",
|
"o6Uy3d": "Only the secret key can be used to publish (sign events), everything else logs you in read-only mode.",
|
||||||
@ -271,6 +278,7 @@
|
|||||||
"u4bHcR": "Check out the code here: {link}",
|
"u4bHcR": "Check out the code here: {link}",
|
||||||
"uD/N6c": "Zap {target} {n} sats",
|
"uD/N6c": "Zap {target} {n} sats",
|
||||||
"uSV4Ti": "Reposts need to be manually confirmed",
|
"uSV4Ti": "Reposts need to be manually confirmed",
|
||||||
|
"ubtr9S": "Can't login with private key on 'http://' connection, please use a Nostr key manager extension instead",
|
||||||
"usAvMr": "Edit Profile",
|
"usAvMr": "Edit Profile",
|
||||||
"ut+2Cd": "Get a partner identifier",
|
"ut+2Cd": "Get a partner identifier",
|
||||||
"vOKedj": "{n,plural,=1{& {n} other} other{& {n} others}}",
|
"vOKedj": "{n,plural,=1{& {n} other} other{& {n} others}}",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user