>
diff --git a/src/feed/EventPublisher.js b/src/feed/EventPublisher.js
index 792f1a2a..45f1789b 100644
--- a/src/feed/EventPublisher.js
+++ b/src/feed/EventPublisher.js
@@ -22,7 +22,6 @@ export default function useEventPublisher() {
if (nip07 === true && hasNip07) {
ev.Id = await ev.CreateId();
let tmpEv = await window.nostr.signEvent(ev.ToObject());
- console.log(tmpEv);
return Event.FromObject(tmpEv);
} else {
await ev.Sign(privKey);
diff --git a/src/index.css b/src/index.css
index e3ca0af1..62039705 100644
--- a/src/index.css
+++ b/src/index.css
@@ -172,4 +172,8 @@ body.scroll-lock {
.tabs > div {
margin-right: 10px;
+}
+
+.error {
+ color: red;
}
\ No newline at end of file
diff --git a/src/pages/Login.js b/src/pages/Login.js
index f8f2b706..14318156 100644
--- a/src/pages/Login.js
+++ b/src/pages/Login.js
@@ -4,13 +4,16 @@ import { useNavigate } from "react-router-dom";
import * as secp from '@noble/secp256k1';
import { bech32 } from "bech32";
-import { setPrivateKey, setNip07PubKey } from "../state/Login";
+import { setPrivateKey, setPublicKey } from "../state/Login";
+
+const EmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
export default function LoginPage() {
const dispatch = useDispatch();
const navigate = useNavigate();
const publicKey = useSelector(s => s.login.publicKey);
const [key, setKey] = useState("");
+ const [error, setError] = useState("");
useEffect(() => {
if (publicKey) {
@@ -18,22 +21,51 @@ export default function LoginPage() {
}
}, [publicKey]);
- function doLogin() {
- if (key.startsWith("nsec")) {
- let nKey = bech32.decode(key);
- let buff = bech32.fromWords(nKey.words);
- let hexKey = secp.utils.bytesToHex(Uint8Array.from(buff));
- if (secp.utils.isValidPrivateKey(hexKey)) {
- dispatch(setPrivateKey(hexKey));
- } else {
- throw "INVALID PRIVATE KEY";
+ function bech32ToHex(str) {
+ let nKey = bech32.decode(str);
+ let buff = bech32.fromWords(nKey.words);
+ return secp.utils.bytesToHex(Uint8Array.from(buff));
+ }
+
+ async function getNip05PubKey(addr) {
+ let [username, domain] = addr.split("@");
+ let rsp = await fetch(`https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(username)}`);
+ if (rsp.ok) {
+ let data = await rsp.json();
+ let pKey = data.names[username];
+ if (pKey) {
+ return pKey;
}
- } else {
- if (secp.utils.isValidPrivateKey(key)) {
- dispatch(setPrivateKey(key));
+ }
+ throw "User key not found"
+ }
+
+ async function doLogin() {
+
+ try {
+ if (key.startsWith("nsec")) {
+ let hexKey = bech32ToHex(key);
+ if (secp.utils.isValidPrivateKey(hexKey)) {
+ dispatch(setPrivateKey(hexKey));
+ } else {
+ throw "INVALID PRIVATE KEY";
+ }
+ } else if (key.startsWith("npub")) {
+ let hexKey = bech32ToHex(key);
+ dispatch(setPublicKey(hexKey));
+ } else if (key.match(EmailRegex)) {
+ let hexKey = await getNip05PubKey(key);
+ dispatch(setPublicKey(hexKey));
} else {
- throw "INVALID PRIVATE KEY";
+ if (secp.utils.isValidPrivateKey(key)) {
+ dispatch(setPrivateKey(key));
+ } else {
+ throw "INVALID PRIVATE KEY";
+ }
}
+ } catch (e) {
+ setError(`Failed to load NIP-05 pub key (${e})`);
+ console.error(e);
}
}
@@ -45,7 +77,7 @@ export default function LoginPage() {
async function doNip07Login() {
let pubKey = await window.nostr.getPublicKey();
- dispatch(setNip07PubKey(pubKey));
+ dispatch(setPublicKey(pubKey));
}
function altLogins() {
@@ -67,10 +99,10 @@ export default function LoginPage() {
return (
<>
doLogin()}>Login
makeRandomKey()}>Generate Key
diff --git a/src/pages/Root.css b/src/pages/Root.css
deleted file mode 100644
index 1a59296d..00000000
--- a/src/pages/Root.css
+++ /dev/null
@@ -1,16 +0,0 @@
-.send-note {
- display: flex;
- margin-bottom: 10px;
-}
-
-.send-note > input[type="text"] {
- flex-grow: 1;
-}
-
-.send-note > .btn {
- margin: 0 5px;
-}
-
-.login {
- margin-bottom: 10px;
-}
\ No newline at end of file
diff --git a/src/pages/Root.js b/src/pages/Root.js
index 883174a9..2659d26f 100644
--- a/src/pages/Root.js
+++ b/src/pages/Root.js
@@ -1,4 +1,3 @@
-import "./Root.css";
import { useSelector } from "react-redux";
import Note from "../element/Note";
import useTimelineFeed from "../feed/TimelineFeed";
@@ -19,9 +18,7 @@ export default function RootPage() {
<>
{pubKey ?
: null}
{followHints()}
-
- {notes?.sort((a, b) => b.created_at - a.created_at).map(e => )}
-
+ {notes?.sort((a, b) => b.created_at - a.created_at).map(e =>
)}
>
);
}
\ No newline at end of file
diff --git a/src/state/Login.js b/src/state/Login.js
index 5b09c7bd..0308fcbe 100644
--- a/src/state/Login.js
+++ b/src/state/Login.js
@@ -2,7 +2,7 @@ import { createSlice } from '@reduxjs/toolkit'
import * as secp from '@noble/secp256k1';
const PrivateKeyItem = "secret";
-const Nip07PublicKeyItem = "nip07:pubkey";
+const PublicKeyItem = "pubkey";
const NotificationsReadItem = "notifications-read";
const LoginSlice = createSlice({
@@ -33,11 +33,6 @@ const LoginSlice = createSlice({
*/
follows: [],
- /**
- * Login keys are managed by extension
- */
- nip07: false,
-
/**
* Notifications for this login session
*/
@@ -52,7 +47,7 @@ const LoginSlice = createSlice({
init: (state) => {
state.privateKey = window.localStorage.getItem(PrivateKeyItem);
if (state.privateKey) {
- window.localStorage.removeItem(Nip07PublicKeyItem); // reset nip07 if using private key
+ window.localStorage.removeItem(PublicKeyItem); // reset nip07 if using private key
state.publicKey = secp.utils.bytesToHex(secp.schnorr.getPublicKey(state.privateKey, true));
state.loggedOut = false;
} else {
@@ -65,11 +60,10 @@ const LoginSlice = createSlice({
"wss://nostr-pub.wellorder.net": { read: true, write: true }
};
- // check nip07 pub key
- let nip07PubKey = window.localStorage.getItem(Nip07PublicKeyItem);
- if (nip07PubKey && !state.privateKey) {
- state.publicKey = nip07PubKey;
- state.nip07 = true;
+ // check pub key only
+ let pubKey = window.localStorage.getItem(PublicKeyItem);
+ if (pubKey && !state.privateKey) {
+ state.publicKey = pubKey;
state.loggedOut = false;
}
@@ -80,18 +74,16 @@ const LoginSlice = createSlice({
}
},
setPrivateKey: (state, action) => {
+ state.loggedOut = false;
state.privateKey = action.payload;
window.localStorage.setItem(PrivateKeyItem, action.payload);
state.publicKey = secp.utils.bytesToHex(secp.schnorr.getPublicKey(action.payload, true));
},
setPublicKey: (state, action) => {
+ window.localStorage.setItem(PublicKeyItem, action.payload);
+ state.loggedOut = false;
state.publicKey = action.payload;
},
- setNip07PubKey: (state, action) => {
- window.localStorage.setItem(Nip07PublicKeyItem, action.payload);
- state.publicKey = action.payload;
- state.nip07 = true;
- },
setRelays: (state, action) => {
// filter out non-websocket urls
let filtered = Object.entries(action.payload)
@@ -119,12 +111,14 @@ const LoginSlice = createSlice({
},
logout: (state) => {
window.localStorage.removeItem(PrivateKeyItem);
- window.localStorage.removeItem(Nip07PublicKeyItem);
+ window.localStorage.removeItem(PublicKeyItem);
+ window.localStorage.removeItem(NotificationsReadItem);
state.privateKey = null;
state.publicKey = null;
state.follows = [];
state.notifications = [];
state.loggedOut = true;
+ state.readNotifications = 0;
},
markNotificationsRead: (state) => {
state.readNotifications = new Date().getTime();
@@ -133,5 +127,5 @@ const LoginSlice = createSlice({
}
});
-export const { init, setPrivateKey, setPublicKey, setNip07PubKey, setRelays, setFollows, addNotifications, logout, markNotificationsRead } = LoginSlice.actions;
+export const { init, setPrivateKey, setPublicKey, setRelays, setFollows, addNotifications, logout, markNotificationsRead } = LoginSlice.actions;
export const reducer = LoginSlice.reducer;
\ No newline at end of file